[
  {
    "path": ".editorconfig",
    "content": "[*]\nindent_style = space\nindent_size = 4\n"
  },
  {
    "path": ".github/workflows/codeql.yml",
    "content": "name: \"CodeQL\"\n\non:\n  push:\n    branches: [ \"master\" ]\n  pull_request:\n    branches: [ \"master\" ]\n  schedule:\n    - cron: \"32 17 * * 5\"\n\njobs:\n  analyze:\n    name: Analyze\n    runs-on: ubuntu-latest\n    permissions:\n      actions: read\n      contents: read\n      security-events: write\n\n    strategy:\n      fail-fast: false\n      matrix:\n        language: [ cpp ]\n\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v3\n\n      - name: Initialize CodeQL\n        uses: github/codeql-action/init@v2\n        with:\n          languages: ${{ matrix.language }}\n          queries: +security-and-quality\n\n      - name: Autobuild\n        uses: github/codeql-action/autobuild@v2\n\n      - name: Perform CodeQL Analysis\n        uses: github/codeql-action/analyze@v2\n        with:\n          category: \"/language:${{ matrix.language }}\"\n"
  },
  {
    "path": ".gitignore",
    "content": "# Compiled Object files\n*.slo\n*.lo\n*.o\n*.obj\n\n# Precompiled Headers\n*.gch\n*.pch\n\n# Compiled Dynamic libraries\n*.so\n*.dylib\n*.dll\n\n# Fortran module files\n*.mod\n\n# Compiled Static libraries\n*.lai\n*.la\n*.a\n*.lib\n\n# Executables\n*.exe\n*.out\n*.app\nbuild*/\ndocumentation/html/\n.gdbinit\nnode_modules/\n\n*.pcapng\n/.vs\n"
  },
  {
    "path": ".gitlab-ci.yml",
    "content": "before_script:\n    - apt-get update -qq\n    - c++ -v\n\ntests:\n    script:\n        - cd bluetoe\n        - mkdir build && cd build && cmake .. && make && ctest"
  },
  {
    "path": ".travis.yml",
    "content": "sudo: required\ndist: bionic\nlanguage: cpp\n\nnotifications:\n  email:\n    on_success: change\n    on_failure: change\n\n# matrix:\n#   include:\n    # - compiler: gcc\n    #   addons:\n    #     apt:\n    #       sources:\n    #         - ubuntu-toolchain-r-test\n    #       packages:\n    #         - g++\n    #   env: COMPILER=g++\n    # - compiler: gcc\n    #   addons:\n    #     apt:\n    #       sources:\n    #         - ubuntu-toolchain-r-test\n    #       packages:\n    #         - g++-5\n    #   env: COMPILER=g++-5\n    # - compiler: clang\n    #   addons:\n    #     apt:\n    #       sources:\n    #         - ubuntu-toolchain-r-test\n    #         - llvm-toolchain-precise-3.6\n    #       packages:\n    #         - clang-3.6\n    #   env: COMPILER=clang++-3.6\n    # - compiler: clang\n    #   addons:\n    #     apt:\n    #       sources:\n    #         - ubuntu-toolchain-r-test\n    #         - llvm-toolchain-precise-3.7\n    #       packages:\n    #         - clang-3.7\n    #   env: COMPILER=clang++-3.7\n\nenv:\n    global:\n        COMPILER=g++\n        BUILD_ON_TRAVIS=1\n        BUILD_DOXYGEN_COMPILE=g++\n\nscript:\n  - $COMPILER -v\n  - mkdir build\n  - cd build\n  - /opt/cmake/bin/cmake --version\n  - /opt/cmake/bin/cmake -DCMAKE_CXX_COMPILER=$COMPILER -DBLUETOE_EXCLUDE_SLOW_TESTS=1 -DBLUETOE_BUILD_UNIT_TESTS=1 ..\n  - make\n  - ctest --verbose\n\nafter_success:\n  - cd $TRAVIS_BUILD_DIR\n  # - sudo apt-get install --yes graphviz\n  # - ls -la\n  # - pwd\n  # - doxygen -v\n  # - ./publish-doxygen\n\nbefore_install:\n  - sudo apt-get update -qq\n  - wget https://github.com/Kitware/CMake/releases/download/v3.19.4/cmake-3.19.4-Linux-x86_64.sh\n  - wget https://cmake.org/files/v3.11/cmake-3.11.4-Linux-x86_64.sh\n  - mkdir /opt/cmake\n  - sh cmake-3.19.4-Linux-x86_64.sh --prefix=/opt/cmake --skip-license\n  - wget https://launchpad.net/%7Eboost-latest/+archive/ubuntu/ppa/+files/libboost1.55-dev_1.55.0-1ppa1%7Esaucy1_amd64.deb\n  - sudo dpkg --install libboost1.55-dev_1.55.0-1ppa1~saucy1_amd64.deb\n  # - openssl aes-256-cbc -K $encrypted_eb6359394db6_key -iv $encrypted_eb6359394db6_iv -in config/travisci_rsa.enc -out config/travisci_rsa -d\n"
  },
  {
    "path": "CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.13)\n\n# Prevent in source build, add this options before project keyword\nset(CMAKE_DISABLE_SOURCE_CHANGES ON)\nset(CMAKE_DISABLE_IN_SOURCE_BUILD ON)\nproject(lib_bluetoe CXX)\n\noption(BLUETOE_BUILD_UNIT_TESTS \"If true, unit test targets are added are build.\")\n\n# Libray required by everything in Bluetoe. If there is need to add build options,\n# add them on bluetoe::iface.\nadd_library(bluetoe_iface INTERFACE)\nadd_library(bluetoe::iface ALIAS bluetoe_iface)\ntarget_compile_features(bluetoe_iface INTERFACE cxx_std_11)\ntarget_include_directories(bluetoe_iface INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})\n\n# Link Layer implementation based on radio hardware\nadd_subdirectory(bluetoe/link_layer)\n\n# Link Layer implementation based on HCI over some serial interface\nadd_subdirectory(bluetoe/hci)\n\n# Utilities\nadd_subdirectory(bluetoe/utility)\n\n# Security Manager\nadd_subdirectory(bluetoe/sm)\n\n# Predefined Services (like DIS, CSC and so on)\nadd_subdirectory(bluetoe/services)\n\nif (CMAKE_CROSSCOMPILING)\n    add_subdirectory(bluetoe/bindings/nordic)\nendif()\n\nif (NOT CMAKE_CROSSCOMPILING AND BLUETOE_BUILD_UNIT_TESTS)\n    enable_testing()\n    add_subdirectory(tests)\nendif()\n\n"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "content": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nIn the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.\n\n## Our Standards\n\nExamples of behavior that contributes to creating a positive environment include:\n\n* Using welcoming and inclusive language\n* Being respectful of differing viewpoints and experiences\n* Gracefully accepting constructive criticism\n* Focusing on what is best for the community\n* Showing empathy towards other community members\n\nExamples of unacceptable behavior by participants include:\n\n* The use of sexualized language or imagery and unwelcome sexual attention or advances\n* Trolling, insulting/derogatory comments, and personal or political attacks\n* Public or private harassment\n* Publishing others' private information, such as a physical or electronic address, without explicit permission\n* Other conduct which could reasonably be considered inappropriate in a professional setting\n\n## Our Responsibilities\n\nProject maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.\n\nProject maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.\n\n## Scope\n\nThis Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.\n\n## Enforcement\n\nInstances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at Torsten At Robitzki dot de. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.\n\nProject maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.\n\n## Attribution\n\nThis Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]\n\n[homepage]: http://contributor-covenant.org\n[version]: http://contributor-covenant.org/version/1/4/\n"
  },
  {
    "path": "Doxyfile",
    "content": "# Doxyfile 1.9.6\n\n# This file describes the settings to be used by the documentation system\n# doxygen (www.doxygen.org) for a project.\n#\n# All text after a double hash (##) is considered a comment and is placed in\n# front of the TAG it is preceding.\n#\n# All text after a single hash (#) is considered a comment and will be ignored.\n# The format is:\n# TAG = value [value, ...]\n# For lists, items can also be appended using:\n# TAG += value [value, ...]\n# Values that contain spaces should be placed between quotes (\\\" \\\").\n#\n# Note:\n#\n# Use doxygen to compare the used configuration file with the template\n# configuration file:\n# doxygen -x [configFile]\n# Use doxygen to compare the used configuration file with the template\n# configuration file without replacing the environment variables or CMake type\n# replacement variables:\n# doxygen -x_noenv [configFile]\n\n#---------------------------------------------------------------------------\n# Project related configuration options\n#---------------------------------------------------------------------------\n\n# This tag specifies the encoding used for all characters in the configuration\n# file that follow. The default is UTF-8 which is also the encoding used for all\n# text before the first occurrence of this tag. Doxygen uses libiconv (or the\n# iconv built into libc) for the transcoding. See\n# https://www.gnu.org/software/libiconv/ for the list of possible encodings.\n# The default value is: UTF-8.\n\nDOXYFILE_ENCODING      = UTF-8\n\n# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by\n# double-quotes, unless you are using Doxywizard) that should identify the\n# project for which the documentation is generated. This name is used in the\n# title of most generated pages and in a few other places.\n# The default value is: My Project.\n\nPROJECT_NAME           = BlueToe\n\n# The PROJECT_NUMBER tag can be used to enter a project or revision number. This\n# could be handy for archiving the generated documentation or if some version\n# control system is used.\n\nPROJECT_NUMBER         =\n\n# Using the PROJECT_BRIEF tag one can provide an optional one line description\n# for a project that appears at the top of each page and should give viewer a\n# quick idea about the purpose of the project. Keep the description short.\n\nPROJECT_BRIEF          = \"an alternative GATT/BLE implementation\"\n\n# With the PROJECT_LOGO tag one can specify a logo or an icon that is included\n# in the documentation. The maximum height of the logo should not exceed 55\n# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy\n# the logo to the output directory.\n\nPROJECT_LOGO           = documentation/Logo_Bluetoe.svg\n\n# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path\n# into which the generated documentation will be written. If a relative path is\n# entered, it will be relative to the location where doxygen was started. If\n# left blank the current directory will be used.\n\nOUTPUT_DIRECTORY       = documentation/\n\n# If the CREATE_SUBDIRS tag is set to YES then doxygen will create up to 4096\n# sub-directories (in 2 levels) under the output directory of each output format\n# and will distribute the generated files over these directories. Enabling this\n# option can be useful when feeding doxygen a huge amount of source files, where\n# putting all generated files in the same directory would otherwise causes\n# performance problems for the file system. Adapt CREATE_SUBDIRS_LEVEL to\n# control the number of sub-directories.\n# The default value is: NO.\n\nCREATE_SUBDIRS         = NO\n\n# Controls the number of sub-directories that will be created when\n# CREATE_SUBDIRS tag is set to YES. Level 0 represents 16 directories, and every\n# level increment doubles the number of directories, resulting in 4096\n# directories at level 8 which is the default and also the maximum value. The\n# sub-directories are organized in 2 levels, the first level always has a fixed\n# number of 16 directories.\n# Minimum value: 0, maximum value: 8, default value: 8.\n# This tag requires that the tag CREATE_SUBDIRS is set to YES.\n\nCREATE_SUBDIRS_LEVEL   = 8\n\n# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII\n# characters to appear in the names of generated files. If set to NO, non-ASCII\n# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode\n# U+3044.\n# The default value is: NO.\n\nALLOW_UNICODE_NAMES    = NO\n\n# The OUTPUT_LANGUAGE tag is used to specify the language in which all\n# documentation generated by doxygen is written. Doxygen will use this\n# information to generate all constant output in the proper language.\n# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Bulgarian,\n# Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, Dutch, English\n# (United States), Esperanto, Farsi (Persian), Finnish, French, German, Greek,\n# Hindi, Hungarian, Indonesian, Italian, Japanese, Japanese-en (Japanese with\n# English messages), Korean, Korean-en (Korean with English messages), Latvian,\n# Lithuanian, Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese,\n# Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish,\n# Swedish, Turkish, Ukrainian and Vietnamese.\n# The default value is: English.\n\nOUTPUT_LANGUAGE        = English\n\n# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member\n# descriptions after the members that are listed in the file and class\n# documentation (similar to Javadoc). Set to NO to disable this.\n# The default value is: YES.\n\nBRIEF_MEMBER_DESC      = YES\n\n# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief\n# description of a member or function before the detailed description\n#\n# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the\n# brief descriptions will be completely suppressed.\n# The default value is: YES.\n\nREPEAT_BRIEF           = YES\n\n# This tag implements a quasi-intelligent brief description abbreviator that is\n# used to form the text in various listings. Each string in this list, if found\n# as the leading text of the brief description, will be stripped from the text\n# and the result, after processing the whole list, is used as the annotated\n# text. Otherwise, the brief description is used as-is. If left blank, the\n# following values are used ($name is automatically replaced with the name of\n# the entity):The $name class, The $name widget, The $name file, is, provides,\n# specifies, contains, represents, a, an and the.\n\nABBREVIATE_BRIEF       =\n\n# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then\n# doxygen will generate a detailed section even if there is only a brief\n# description.\n# The default value is: NO.\n\nALWAYS_DETAILED_SEC    = NO\n\n# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all\n# inherited members of a class in the documentation of that class as if those\n# members were ordinary class members. Constructors, destructors and assignment\n# operators of the base classes will not be shown.\n# The default value is: NO.\n\nINLINE_INHERITED_MEMB  = NO\n\n# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path\n# before files name in the file list and in the header files. If set to NO the\n# shortest path that makes the file name unique will be used\n# The default value is: YES.\n\nFULL_PATH_NAMES        = YES\n\n# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.\n# Stripping is only done if one of the specified strings matches the left-hand\n# part of the path. The tag can be used to show relative paths in the file list.\n# If left blank the directory from which doxygen is run is used as the path to\n# strip.\n#\n# Note that you can specify absolute paths here, but also relative paths, which\n# will be relative from the directory where doxygen is started.\n# This tag requires that the tag FULL_PATH_NAMES is set to YES.\n\nSTRIP_FROM_PATH        = .\n\n# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the\n# path mentioned in the documentation of a class, which tells the reader which\n# header file to include in order to use a class. If left blank only the name of\n# the header file containing the class definition is used. Otherwise one should\n# specify the list of include paths that are normally passed to the compiler\n# using the -I flag.\n\nSTRIP_FROM_INC_PATH    = .\n\n# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but\n# less readable) file names. This can be useful is your file systems doesn't\n# support long names like on DOS, Mac, or CD-ROM.\n# The default value is: NO.\n\nSHORT_NAMES            = NO\n\n# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the\n# first line (until the first dot) of a Javadoc-style comment as the brief\n# description. If set to NO, the Javadoc-style will behave just like regular Qt-\n# style comments (thus requiring an explicit @brief command for a brief\n# description.)\n# The default value is: NO.\n\nJAVADOC_AUTOBRIEF      = NO\n\n# If the JAVADOC_BANNER tag is set to YES then doxygen will interpret a line\n# such as\n# /***************\n# as being the beginning of a Javadoc-style comment \"banner\". If set to NO, the\n# Javadoc-style will behave just like regular comments and it will not be\n# interpreted by doxygen.\n# The default value is: NO.\n\nJAVADOC_BANNER         = NO\n\n# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first\n# line (until the first dot) of a Qt-style comment as the brief description. If\n# set to NO, the Qt-style will behave just like regular Qt-style comments (thus\n# requiring an explicit \\brief command for a brief description.)\n# The default value is: NO.\n\nQT_AUTOBRIEF           = NO\n\n# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a\n# multi-line C++ special comment block (i.e. a block of //! or /// comments) as\n# a brief description. This used to be the default behavior. The new default is\n# to treat a multi-line C++ comment block as a detailed description. Set this\n# tag to YES if you prefer the old behavior instead.\n#\n# Note that setting this tag to YES also means that rational rose comments are\n# not recognized any more.\n# The default value is: NO.\n\nMULTILINE_CPP_IS_BRIEF = NO\n\n# By default Python docstrings are displayed as preformatted text and doxygen's\n# special commands cannot be used. By setting PYTHON_DOCSTRING to NO the\n# doxygen's special commands can be used and the contents of the docstring\n# documentation blocks is shown as doxygen documentation.\n# The default value is: YES.\n\nPYTHON_DOCSTRING       = YES\n\n# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the\n# documentation from any documented member that it re-implements.\n# The default value is: YES.\n\nINHERIT_DOCS           = YES\n\n# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new\n# page for each member. If set to NO, the documentation of a member will be part\n# of the file/class/namespace that contains it.\n# The default value is: NO.\n\nSEPARATE_MEMBER_PAGES  = NO\n\n# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen\n# uses this value to replace tabs by spaces in code fragments.\n# Minimum value: 1, maximum value: 16, default value: 4.\n\nTAB_SIZE               = 4\n\n# This tag can be used to specify a number of aliases that act as commands in\n# the documentation. An alias has the form:\n# name=value\n# For example adding\n# \"sideeffect=@par Side Effects:^^\"\n# will allow you to put the command \\sideeffect (or @sideeffect) in the\n# documentation, which will result in a user-defined paragraph with heading\n# \"Side Effects:\". Note that you cannot put \\n's in the value part of an alias\n# to insert newlines (in the resulting output). You can put ^^ in the value part\n# of an alias to insert a newline as if a physical newline was in the original\n# file. When you need a literal { or } or , in the value part of an alias you\n# have to escape them by means of a backslash (\\), this can lead to conflicts\n# with the commands \\{ and \\} for these it is advised to use the version @{ and\n# @} or use a double escape (\\\\{ and \\\\})\n\nALIASES                =\n\n# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources\n# only. Doxygen will then generate output that is more tailored for C. For\n# instance, some of the names that are used will be different. The list of all\n# members will be omitted, etc.\n# The default value is: NO.\n\nOPTIMIZE_OUTPUT_FOR_C  = NO\n\n# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or\n# Python sources only. Doxygen will then generate output that is more tailored\n# for that language. For instance, namespaces will be presented as packages,\n# qualified scopes will look different, etc.\n# The default value is: NO.\n\nOPTIMIZE_OUTPUT_JAVA   = NO\n\n# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran\n# sources. Doxygen will then generate output that is tailored for Fortran.\n# The default value is: NO.\n\nOPTIMIZE_FOR_FORTRAN   = NO\n\n# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL\n# sources. Doxygen will then generate output that is tailored for VHDL.\n# The default value is: NO.\n\nOPTIMIZE_OUTPUT_VHDL   = NO\n\n# Set the OPTIMIZE_OUTPUT_SLICE tag to YES if your project consists of Slice\n# sources only. Doxygen will then generate output that is more tailored for that\n# language. For instance, namespaces will be presented as modules, types will be\n# separated into more groups, etc.\n# The default value is: NO.\n\nOPTIMIZE_OUTPUT_SLICE  = NO\n\n# Doxygen selects the parser to use depending on the extension of the files it\n# parses. With this tag you can assign which parser to use for a given\n# extension. Doxygen has a built-in mapping, but you can override or extend it\n# using this tag. The format is ext=language, where ext is a file extension, and\n# language is one of the parsers supported by doxygen: IDL, Java, JavaScript,\n# Csharp (C#), C, C++, Lex, D, PHP, md (Markdown), Objective-C, Python, Slice,\n# VHDL, Fortran (fixed format Fortran: FortranFixed, free formatted Fortran:\n# FortranFree, unknown formatted Fortran: Fortran. In the later case the parser\n# tries to guess whether the code is fixed or free formatted code, this is the\n# default for Fortran type files). For instance to make doxygen treat .inc files\n# as Fortran files (default is PHP), and .f files as C (default is Fortran),\n# use: inc=Fortran f=C.\n#\n# Note: For files without extension you can use no_extension as a placeholder.\n#\n# Note that for custom extensions you also need to set FILE_PATTERNS otherwise\n# the files are not read by doxygen. When specifying no_extension you should add\n# * to the FILE_PATTERNS.\n#\n# Note see also the list of default file extension mappings.\n\nEXTENSION_MAPPING      =\n\n# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments\n# according to the Markdown format, which allows for more readable\n# documentation. See https://daringfireball.net/projects/markdown/ for details.\n# The output of markdown processing is further processed by doxygen, so you can\n# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in\n# case of backward compatibilities issues.\n# The default value is: YES.\n\nMARKDOWN_SUPPORT       = YES\n\n# When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up\n# to that level are automatically included in the table of contents, even if\n# they do not have an id attribute.\n# Note: This feature currently applies only to Markdown headings.\n# Minimum value: 0, maximum value: 99, default value: 5.\n# This tag requires that the tag MARKDOWN_SUPPORT is set to YES.\n\nTOC_INCLUDE_HEADINGS   = 5\n\n# When enabled doxygen tries to link words that correspond to documented\n# classes, or namespaces to their corresponding documentation. Such a link can\n# be prevented in individual cases by putting a % sign in front of the word or\n# globally by setting AUTOLINK_SUPPORT to NO.\n# The default value is: YES.\n\nAUTOLINK_SUPPORT       = YES\n\n# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want\n# to include (a tag file for) the STL sources as input, then you should set this\n# tag to YES in order to let doxygen match functions declarations and\n# definitions whose arguments contain STL classes (e.g. func(std::string);\n# versus func(std::string) {}). This also make the inheritance and collaboration\n# diagrams that involve STL classes more complete and accurate.\n# The default value is: NO.\n\nBUILTIN_STL_SUPPORT    = NO\n\n# If you use Microsoft's C++/CLI language, you should set this option to YES to\n# enable parsing support.\n# The default value is: NO.\n\nCPP_CLI_SUPPORT        = NO\n\n# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:\n# https://www.riverbankcomputing.com/software/sip/intro) sources only. Doxygen\n# will parse them like normal C++ but will assume all classes use public instead\n# of private inheritance when no explicit protection keyword is present.\n# The default value is: NO.\n\nSIP_SUPPORT            = NO\n\n# For Microsoft's IDL there are propget and propput attributes to indicate\n# getter and setter methods for a property. Setting this option to YES will make\n# doxygen to replace the get and set methods by a property in the documentation.\n# This will only work if the methods are indeed getting or setting a simple\n# type. If this is not the case, or you want to show the methods anyway, you\n# should set this option to NO.\n# The default value is: YES.\n\nIDL_PROPERTY_SUPPORT   = YES\n\n# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC\n# tag is set to YES then doxygen will reuse the documentation of the first\n# member in the group (if any) for the other members of the group. By default\n# all members of a group must be documented explicitly.\n# The default value is: NO.\n\nDISTRIBUTE_GROUP_DOC   = NO\n\n# If one adds a struct or class to a group and this option is enabled, then also\n# any nested class or struct is added to the same group. By default this option\n# is disabled and one has to add nested compounds explicitly via \\ingroup.\n# The default value is: NO.\n\nGROUP_NESTED_COMPOUNDS = NO\n\n# Set the SUBGROUPING tag to YES to allow class member groups of the same type\n# (for instance a group of public functions) to be put as a subgroup of that\n# type (e.g. under the Public Functions section). Set it to NO to prevent\n# subgrouping. Alternatively, this can be done per class using the\n# \\nosubgrouping command.\n# The default value is: YES.\n\nSUBGROUPING            = YES\n\n# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions\n# are shown inside the group in which they are included (e.g. using \\ingroup)\n# instead of on a separate page (for HTML and Man pages) or section (for LaTeX\n# and RTF).\n#\n# Note that this feature does not work in combination with\n# SEPARATE_MEMBER_PAGES.\n# The default value is: NO.\n\nINLINE_GROUPED_CLASSES = NO\n\n# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions\n# with only public data fields or simple typedef fields will be shown inline in\n# the documentation of the scope in which they are defined (i.e. file,\n# namespace, or group documentation), provided this scope is documented. If set\n# to NO, structs, classes, and unions are shown on a separate page (for HTML and\n# Man pages) or section (for LaTeX and RTF).\n# The default value is: NO.\n\nINLINE_SIMPLE_STRUCTS  = NO\n\n# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or\n# enum is documented as struct, union, or enum with the name of the typedef. So\n# typedef struct TypeS {} TypeT, will appear in the documentation as a struct\n# with name TypeT. When disabled the typedef will appear as a member of a file,\n# namespace, or class. And the struct will be named TypeS. This can typically be\n# useful for C code in case the coding convention dictates that all compound\n# types are typedef'ed and only the typedef is referenced, never the tag name.\n# The default value is: NO.\n\nTYPEDEF_HIDES_STRUCT   = NO\n\n# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This\n# cache is used to resolve symbols given their name and scope. Since this can be\n# an expensive process and often the same symbol appears multiple times in the\n# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small\n# doxygen will become slower. If the cache is too large, memory is wasted. The\n# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range\n# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536\n# symbols. At the end of a run doxygen will report the cache usage and suggest\n# the optimal cache size from a speed point of view.\n# Minimum value: 0, maximum value: 9, default value: 0.\n\nLOOKUP_CACHE_SIZE      = 0\n\n# The NUM_PROC_THREADS specifies the number of threads doxygen is allowed to use\n# during processing. When set to 0 doxygen will based this on the number of\n# cores available in the system. You can set it explicitly to a value larger\n# than 0 to get more control over the balance between CPU load and processing\n# speed. At this moment only the input processing can be done using multiple\n# threads. Since this is still an experimental feature the default is set to 1,\n# which effectively disables parallel processing. Please report any issues you\n# encounter. Generating dot graphs in parallel is controlled by the\n# DOT_NUM_THREADS setting.\n# Minimum value: 0, maximum value: 32, default value: 1.\n\nNUM_PROC_THREADS       = 1\n\n#---------------------------------------------------------------------------\n# Build related configuration options\n#---------------------------------------------------------------------------\n\n# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in\n# documentation are documented, even if no documentation was available. Private\n# class members and static file members will be hidden unless the\n# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.\n# Note: This will also disable the warnings about undocumented members that are\n# normally produced when WARNINGS is set to YES.\n# The default value is: NO.\n\nEXTRACT_ALL            = NO\n\n# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will\n# be included in the documentation.\n# The default value is: NO.\n\nEXTRACT_PRIVATE        = NO\n\n# If the EXTRACT_PRIV_VIRTUAL tag is set to YES, documented private virtual\n# methods of a class will be included in the documentation.\n# The default value is: NO.\n\nEXTRACT_PRIV_VIRTUAL   = NO\n\n# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal\n# scope will be included in the documentation.\n# The default value is: NO.\n\nEXTRACT_PACKAGE        = NO\n\n# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be\n# included in the documentation.\n# The default value is: NO.\n\nEXTRACT_STATIC         = NO\n\n# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined\n# locally in source files will be included in the documentation. If set to NO,\n# only classes defined in header files are included. Does not have any effect\n# for Java sources.\n# The default value is: YES.\n\nEXTRACT_LOCAL_CLASSES  = YES\n\n# This flag is only useful for Objective-C code. If set to YES, local methods,\n# which are defined in the implementation section but not in the interface are\n# included in the documentation. If set to NO, only methods in the interface are\n# included.\n# The default value is: NO.\n\nEXTRACT_LOCAL_METHODS  = NO\n\n# If this flag is set to YES, the members of anonymous namespaces will be\n# extracted and appear in the documentation as a namespace called\n# 'anonymous_namespace{file}', where file will be replaced with the base name of\n# the file that contains the anonymous namespace. By default anonymous namespace\n# are hidden.\n# The default value is: NO.\n\nEXTRACT_ANON_NSPACES   = NO\n\n# If this flag is set to YES, the name of an unnamed parameter in a declaration\n# will be determined by the corresponding definition. By default unnamed\n# parameters remain unnamed in the output.\n# The default value is: YES.\n\nRESOLVE_UNNAMED_PARAMS = YES\n\n# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all\n# undocumented members inside documented classes or files. If set to NO these\n# members will be included in the various overviews, but no documentation\n# section is generated. This option has no effect if EXTRACT_ALL is enabled.\n# The default value is: NO.\n\nHIDE_UNDOC_MEMBERS     = NO\n\n# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all\n# undocumented classes that are normally visible in the class hierarchy. If set\n# to NO, these classes will be included in the various overviews. This option\n# will also hide undocumented C++ concepts if enabled. This option has no effect\n# if EXTRACT_ALL is enabled.\n# The default value is: NO.\n\nHIDE_UNDOC_CLASSES     = NO\n\n# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend\n# declarations. If set to NO, these declarations will be included in the\n# documentation.\n# The default value is: NO.\n\nHIDE_FRIEND_COMPOUNDS  = NO\n\n# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any\n# documentation blocks found inside the body of a function. If set to NO, these\n# blocks will be appended to the function's detailed documentation block.\n# The default value is: NO.\n\nHIDE_IN_BODY_DOCS      = NO\n\n# The INTERNAL_DOCS tag determines if documentation that is typed after a\n# \\internal command is included. If the tag is set to NO then the documentation\n# will be excluded. Set it to YES to include the internal documentation.\n# The default value is: NO.\n\nINTERNAL_DOCS          = NO\n\n# With the correct setting of option CASE_SENSE_NAMES doxygen will better be\n# able to match the capabilities of the underlying filesystem. In case the\n# filesystem is case sensitive (i.e. it supports files in the same directory\n# whose names only differ in casing), the option must be set to YES to properly\n# deal with such files in case they appear in the input. For filesystems that\n# are not case sensitive the option should be set to NO to properly deal with\n# output files written for symbols that only differ in casing, such as for two\n# classes, one named CLASS and the other named Class, and to also support\n# references to files without having to specify the exact matching casing. On\n# Windows (including Cygwin) and MacOS, users should typically set this option\n# to NO, whereas on Linux or other Unix flavors it should typically be set to\n# YES.\n# Possible values are: SYSTEM, NO and YES.\n# The default value is: SYSTEM.\n\nCASE_SENSE_NAMES       = NO\n\n# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with\n# their full class and namespace scopes in the documentation. If set to YES, the\n# scope will be hidden.\n# The default value is: NO.\n\nHIDE_SCOPE_NAMES       = NO\n\n# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will\n# append additional text to a page's title, such as Class Reference. If set to\n# YES the compound reference will be hidden.\n# The default value is: NO.\n\nHIDE_COMPOUND_REFERENCE= NO\n\n# If the SHOW_HEADERFILE tag is set to YES then the documentation for a class\n# will show which file needs to be included to use the class.\n# The default value is: YES.\n\nSHOW_HEADERFILE        = YES\n\n# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of\n# the files that are included by a file in the documentation of that file.\n# The default value is: YES.\n\nSHOW_INCLUDE_FILES     = YES\n\n# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each\n# grouped member an include statement to the documentation, telling the reader\n# which file to include in order to use the member.\n# The default value is: NO.\n\nSHOW_GROUPED_MEMB_INC  = NO\n\n# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include\n# files with double quotes in the documentation rather than with sharp brackets.\n# The default value is: NO.\n\nFORCE_LOCAL_INCLUDES   = NO\n\n# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the\n# documentation for inline members.\n# The default value is: YES.\n\nINLINE_INFO            = YES\n\n# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the\n# (detailed) documentation of file and class members alphabetically by member\n# name. If set to NO, the members will appear in declaration order.\n# The default value is: YES.\n\nSORT_MEMBER_DOCS       = YES\n\n# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief\n# descriptions of file, namespace and class members alphabetically by member\n# name. If set to NO, the members will appear in declaration order. Note that\n# this will also influence the order of the classes in the class list.\n# The default value is: NO.\n\nSORT_BRIEF_DOCS        = NO\n\n# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the\n# (brief and detailed) documentation of class members so that constructors and\n# destructors are listed first. If set to NO the constructors will appear in the\n# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.\n# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief\n# member documentation.\n# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting\n# detailed member documentation.\n# The default value is: NO.\n\nSORT_MEMBERS_CTORS_1ST = NO\n\n# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy\n# of group names into alphabetical order. If set to NO the group names will\n# appear in their defined order.\n# The default value is: NO.\n\nSORT_GROUP_NAMES       = NO\n\n# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by\n# fully-qualified names, including namespaces. If set to NO, the class list will\n# be sorted only by class name, not including the namespace part.\n# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.\n# Note: This option applies only to the class list, not to the alphabetical\n# list.\n# The default value is: NO.\n\nSORT_BY_SCOPE_NAME     = NO\n\n# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper\n# type resolution of all parameters of a function it will reject a match between\n# the prototype and the implementation of a member function even if there is\n# only one candidate or it is obvious which candidate to choose by doing a\n# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still\n# accept a match between prototype and implementation in such cases.\n# The default value is: NO.\n\nSTRICT_PROTO_MATCHING  = NO\n\n# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo\n# list. This list is created by putting \\todo commands in the documentation.\n# The default value is: YES.\n\nGENERATE_TODOLIST      = YES\n\n# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test\n# list. This list is created by putting \\test commands in the documentation.\n# The default value is: YES.\n\nGENERATE_TESTLIST      = YES\n\n# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug\n# list. This list is created by putting \\bug commands in the documentation.\n# The default value is: YES.\n\nGENERATE_BUGLIST       = YES\n\n# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO)\n# the deprecated list. This list is created by putting \\deprecated commands in\n# the documentation.\n# The default value is: YES.\n\nGENERATE_DEPRECATEDLIST= YES\n\n# The ENABLED_SECTIONS tag can be used to enable conditional documentation\n# sections, marked by \\if <section_label> ... \\endif and \\cond <section_label>\n# ... \\endcond blocks.\n\nENABLED_SECTIONS       =\n\n# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the\n# initial value of a variable or macro / define can have for it to appear in the\n# documentation. If the initializer consists of more lines than specified here\n# it will be hidden. Use a value of 0 to hide initializers completely. The\n# appearance of the value of individual variables and macros / defines can be\n# controlled using \\showinitializer or \\hideinitializer command in the\n# documentation regardless of this setting.\n# Minimum value: 0, maximum value: 10000, default value: 30.\n\nMAX_INITIALIZER_LINES  = 30\n\n# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at\n# the bottom of the documentation of classes and structs. If set to YES, the\n# list will mention the files that were used to generate the documentation.\n# The default value is: YES.\n\nSHOW_USED_FILES        = YES\n\n# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This\n# will remove the Files entry from the Quick Index and from the Folder Tree View\n# (if specified).\n# The default value is: YES.\n\nSHOW_FILES             = YES\n\n# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces\n# page. This will remove the Namespaces entry from the Quick Index and from the\n# Folder Tree View (if specified).\n# The default value is: YES.\n\nSHOW_NAMESPACES        = YES\n\n# The FILE_VERSION_FILTER tag can be used to specify a program or script that\n# doxygen should invoke to get the current version for each file (typically from\n# the version control system). Doxygen will invoke the program by executing (via\n# popen()) the command command input-file, where command is the value of the\n# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided\n# by doxygen. Whatever the program writes to standard output is used as the file\n# version. For an example see the documentation.\n\nFILE_VERSION_FILTER    =\n\n# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed\n# by doxygen. The layout file controls the global structure of the generated\n# output files in an output format independent way. To create the layout file\n# that represents doxygen's defaults, run doxygen with the -l option. You can\n# optionally specify a file name after the option, if omitted DoxygenLayout.xml\n# will be used as the name of the layout file. See also section \"Changing the\n# layout of pages\" for information.\n#\n# Note that if you run doxygen from a directory containing a file called\n# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE\n# tag is left empty.\n\nLAYOUT_FILE            =\n\n# The CITE_BIB_FILES tag can be used to specify one or more bib files containing\n# the reference definitions. This must be a list of .bib files. The .bib\n# extension is automatically appended if omitted. This requires the bibtex tool\n# to be installed. See also https://en.wikipedia.org/wiki/BibTeX for more info.\n# For LaTeX the style of the bibliography can be controlled using\n# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the\n# search path. See also \\cite for info how to create references.\n\nCITE_BIB_FILES         =\n\n#---------------------------------------------------------------------------\n# Configuration options related to warning and progress messages\n#---------------------------------------------------------------------------\n\n# The QUIET tag can be used to turn on/off the messages that are generated to\n# standard output by doxygen. If QUIET is set to YES this implies that the\n# messages are off.\n# The default value is: NO.\n\nQUIET                  = NO\n\n# The WARNINGS tag can be used to turn on/off the warning messages that are\n# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES\n# this implies that the warnings are on.\n#\n# Tip: Turn warnings on while writing the documentation.\n# The default value is: YES.\n\nWARNINGS               = YES\n\n# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate\n# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag\n# will automatically be disabled.\n# The default value is: YES.\n\nWARN_IF_UNDOCUMENTED   = YES\n\n# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for\n# potential errors in the documentation, such as documenting some parameters in\n# a documented function twice, or documenting parameters that don't exist or\n# using markup commands wrongly.\n# The default value is: YES.\n\nWARN_IF_DOC_ERROR      = YES\n\n# If WARN_IF_INCOMPLETE_DOC is set to YES, doxygen will warn about incomplete\n# function parameter documentation. If set to NO, doxygen will accept that some\n# parameters have no documentation without warning.\n# The default value is: YES.\n\nWARN_IF_INCOMPLETE_DOC = YES\n\n# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that\n# are documented, but have no documentation for their parameters or return\n# value. If set to NO, doxygen will only warn about wrong parameter\n# documentation, but not about the absence of documentation. If EXTRACT_ALL is\n# set to YES then this flag will automatically be disabled. See also\n# WARN_IF_INCOMPLETE_DOC\n# The default value is: NO.\n\nWARN_NO_PARAMDOC       = NO\n\n# If WARN_IF_UNDOC_ENUM_VAL option is set to YES, doxygen will warn about\n# undocumented enumeration values. If set to NO, doxygen will accept\n# undocumented enumeration values. If EXTRACT_ALL is set to YES then this flag\n# will automatically be disabled.\n# The default value is: NO.\n\nWARN_IF_UNDOC_ENUM_VAL = NO\n\n# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when\n# a warning is encountered. If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS\n# then doxygen will continue running as if WARN_AS_ERROR tag is set to NO, but\n# at the end of the doxygen process doxygen will return with a non-zero status.\n# Possible values are: NO, YES and FAIL_ON_WARNINGS.\n# The default value is: NO.\n\nWARN_AS_ERROR          = NO\n\n# The WARN_FORMAT tag determines the format of the warning messages that doxygen\n# can produce. The string should contain the $file, $line, and $text tags, which\n# will be replaced by the file and line number from which the warning originated\n# and the warning text. Optionally the format may contain $version, which will\n# be replaced by the version of the file (if it could be obtained via\n# FILE_VERSION_FILTER)\n# See also: WARN_LINE_FORMAT\n# The default value is: $file:$line: $text.\n\nWARN_FORMAT            = \"$file:$line: $text\"\n\n# In the $text part of the WARN_FORMAT command it is possible that a reference\n# to a more specific place is given. To make it easier to jump to this place\n# (outside of doxygen) the user can define a custom \"cut\" / \"paste\" string.\n# Example:\n# WARN_LINE_FORMAT = \"'vi $file +$line'\"\n# See also: WARN_FORMAT\n# The default value is: at line $line of file $file.\n\nWARN_LINE_FORMAT       = \"at line $line of file $file\"\n\n# The WARN_LOGFILE tag can be used to specify a file to which warning and error\n# messages should be written. If left blank the output is written to standard\n# error (stderr). In case the file specified cannot be opened for writing the\n# warning and error messages are written to standard error. When as file - is\n# specified the warning and error messages are written to standard output\n# (stdout).\n\nWARN_LOGFILE           =\n\n#---------------------------------------------------------------------------\n# Configuration options related to the input files\n#---------------------------------------------------------------------------\n\n# The INPUT tag is used to specify the files and/or directories that contain\n# documented source files. You may enter file names like myfile.cpp or\n# directories like /usr/src/myproject. Separate the files or directories with\n# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING\n# Note: If this tag is empty the current directory is searched.\n\nINPUT                  = bluetoe/\n\n# This tag can be used to specify the character encoding of the source files\n# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses\n# libiconv (or the iconv built into libc) for the transcoding. See the libiconv\n# documentation (see:\n# https://www.gnu.org/software/libiconv/) for the list of possible encodings.\n# See also: INPUT_FILE_ENCODING\n# The default value is: UTF-8.\n\nINPUT_ENCODING         = UTF-8\n\n# This tag can be used to specify the character encoding of the source files\n# that doxygen parses The INPUT_FILE_ENCODING tag can be used to specify\n# character encoding on a per file pattern basis. Doxygen will compare the file\n# name with each pattern and apply the encoding instead of the default\n# INPUT_ENCODING) if there is a match. The character encodings are a list of the\n# form: pattern=encoding (like *.php=ISO-8859-1). See cfg_input_encoding\n# \"INPUT_ENCODING\" for further information on supported encodings.\n\nINPUT_FILE_ENCODING    =\n\n# If the value of the INPUT tag contains directories, you can use the\n# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and\n# *.h) to filter out the source-files in the directories.\n#\n# Note that for custom extensions or not directly supported extensions you also\n# need to set EXTENSION_MAPPING for the extension otherwise the files are not\n# read by doxygen.\n#\n# Note the list of default checked file patterns might differ from the list of\n# default file extension mappings.\n#\n# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp,\n# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h,\n# *.hh, *.hxx, *.hpp, *.h++, *.l, *.cs, *.d, *.php, *.php4, *.php5, *.phtml,\n# *.inc, *.m, *.markdown, *.md, *.mm, *.dox (to be provided as doxygen C\n# comment), *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, *.f18, *.f, *.for, *.vhd,\n# *.vhdl, *.ucf, *.qsf and *.ice.\n\nFILE_PATTERNS          = *.hpp \\\n                         *.md\n\n# The RECURSIVE tag can be used to specify whether or not subdirectories should\n# be searched for input files as well.\n# The default value is: NO.\n\nRECURSIVE              = YES\n\n# The EXCLUDE tag can be used to specify files and/or directories that should be\n# excluded from the INPUT source files. This way you can easily exclude a\n# subdirectory from a directory tree whose root is specified with the INPUT tag.\n#\n# Note that relative paths are relative to the directory from which doxygen is\n# run.\n\nEXCLUDE                =\n\n# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or\n# directories that are symbolic links (a Unix file system feature) are excluded\n# from the input.\n# The default value is: NO.\n\nEXCLUDE_SYMLINKS       = NO\n\n# If the value of the INPUT tag contains directories, you can use the\n# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude\n# certain files from those directories.\n#\n# Note that the wildcards are matched against the file with absolute path, so to\n# exclude all test directories for example use the pattern */test/*\n\nEXCLUDE_PATTERNS       =\n\n# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names\n# (namespaces, classes, functions, etc.) that should be excluded from the\n# output. The symbol name can be a fully qualified name, a word, or if the\n# wildcard * is used, a substring. Examples: ANamespace, AClass,\n# ANamespace::AClass, ANamespace::*Test\n#\n# Note that the wildcards are matched against the file with absolute path, so to\n# exclude all test directories use the pattern */test/*\n\nEXCLUDE_SYMBOLS        = bluetoe::details::* \\\n                         bluetoe::nrf_details::* \\\n                         bluetoe::nrf51_details::* \\\n                         bluetoe::nrf52_details::* \\\n                         bluetoe::link_layer::details::* \\\n                         bluetoe::hid::details::*\n\n# The EXAMPLE_PATH tag can be used to specify one or more files or directories\n# that contain example code fragments that are included (see the \\include\n# command).\n\nEXAMPLE_PATH           = examples/doxygen\n\n# If the value of the EXAMPLE_PATH tag contains directories, you can use the\n# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and\n# *.h) to filter out the source-files in the directories. If left blank all\n# files are included.\n\nEXAMPLE_PATTERNS       =\n\n# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be\n# searched for input files to be used with the \\include or \\dontinclude commands\n# irrespective of the value of the RECURSIVE tag.\n# The default value is: NO.\n\nEXAMPLE_RECURSIVE      = NO\n\n# The IMAGE_PATH tag can be used to specify one or more files or directories\n# that contain images that are to be included in the documentation (see the\n# \\image command).\n\nIMAGE_PATH             =\n\n# The INPUT_FILTER tag can be used to specify a program that doxygen should\n# invoke to filter for each input file. Doxygen will invoke the filter program\n# by executing (via popen()) the command:\n#\n# <filter> <input-file>\n#\n# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the\n# name of an input file. Doxygen will then use the output that the filter\n# program writes to standard output. If FILTER_PATTERNS is specified, this tag\n# will be ignored.\n#\n# Note that the filter must not add or remove lines; it is applied before the\n# code is scanned, but not when the output code is generated. If lines are added\n# or removed, the anchors will not be placed correctly.\n#\n# Note that doxygen will use the data processed and written to standard output\n# for further processing, therefore nothing else, like debug statements or used\n# commands (so in case of a Windows batch file always use @echo OFF), should be\n# written to standard output.\n#\n# Note that for custom extensions or not directly supported extensions you also\n# need to set EXTENSION_MAPPING for the extension otherwise the files are not\n# properly processed by doxygen.\n\nINPUT_FILTER           =\n\n# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern\n# basis. Doxygen will compare the file name with each pattern and apply the\n# filter if there is a match. The filters are a list of the form: pattern=filter\n# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how\n# filters are used. If the FILTER_PATTERNS tag is empty or if none of the\n# patterns match the file name, INPUT_FILTER is applied.\n#\n# Note that for custom extensions or not directly supported extensions you also\n# need to set EXTENSION_MAPPING for the extension otherwise the files are not\n# properly processed by doxygen.\n\nFILTER_PATTERNS        =\n\n# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using\n# INPUT_FILTER) will also be used to filter the input files that are used for\n# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).\n# The default value is: NO.\n\nFILTER_SOURCE_FILES    = NO\n\n# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file\n# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and\n# it is also possible to disable source filtering for a specific pattern using\n# *.ext= (so without naming a filter).\n# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.\n\nFILTER_SOURCE_PATTERNS =\n\n# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that\n# is part of the input, its contents will be placed on the main page\n# (index.html). This can be useful if you have a project on for instance GitHub\n# and want to reuse the introduction page also for the doxygen output.\n\nUSE_MDFILE_AS_MAINPAGE =\n\n# The Fortran standard specifies that for fixed formatted Fortran code all\n# characters from position 72 are to be considered as comment. A common\n# extension is to allow longer lines before the automatic comment starts. The\n# setting FORTRAN_COMMENT_AFTER will also make it possible that longer lines can\n# be processed before the automatic comment starts.\n# Minimum value: 7, maximum value: 10000, default value: 72.\n\nFORTRAN_COMMENT_AFTER  = 72\n\n#---------------------------------------------------------------------------\n# Configuration options related to source browsing\n#---------------------------------------------------------------------------\n\n# If the SOURCE_BROWSER tag is set to YES then a list of source files will be\n# generated. Documented entities will be cross-referenced with these sources.\n#\n# Note: To get rid of all source code in the generated output, make sure that\n# also VERBATIM_HEADERS is set to NO.\n# The default value is: NO.\n\nSOURCE_BROWSER         = NO\n\n# Setting the INLINE_SOURCES tag to YES will include the body of functions,\n# classes and enums directly into the documentation.\n# The default value is: NO.\n\nINLINE_SOURCES         = NO\n\n# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any\n# special comment blocks from generated source code fragments. Normal C, C++ and\n# Fortran comments will always remain visible.\n# The default value is: YES.\n\nSTRIP_CODE_COMMENTS    = YES\n\n# If the REFERENCED_BY_RELATION tag is set to YES then for each documented\n# entity all documented functions referencing it will be listed.\n# The default value is: NO.\n\nREFERENCED_BY_RELATION = NO\n\n# If the REFERENCES_RELATION tag is set to YES then for each documented function\n# all documented entities called/used by that function will be listed.\n# The default value is: NO.\n\nREFERENCES_RELATION    = NO\n\n# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set\n# to YES then the hyperlinks from functions in REFERENCES_RELATION and\n# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will\n# link to the documentation.\n# The default value is: YES.\n\nREFERENCES_LINK_SOURCE = YES\n\n# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the\n# source code will show a tooltip with additional information such as prototype,\n# brief description and links to the definition and documentation. Since this\n# will make the HTML file larger and loading of large files a bit slower, you\n# can opt to disable this feature.\n# The default value is: YES.\n# This tag requires that the tag SOURCE_BROWSER is set to YES.\n\nSOURCE_TOOLTIPS        = YES\n\n# If the USE_HTAGS tag is set to YES then the references to source code will\n# point to the HTML generated by the htags(1) tool instead of doxygen built-in\n# source browser. The htags tool is part of GNU's global source tagging system\n# (see https://www.gnu.org/software/global/global.html). You will need version\n# 4.8.6 or higher.\n#\n# To use it do the following:\n# - Install the latest version of global\n# - Enable SOURCE_BROWSER and USE_HTAGS in the configuration file\n# - Make sure the INPUT points to the root of the source tree\n# - Run doxygen as normal\n#\n# Doxygen will invoke htags (and that will in turn invoke gtags), so these\n# tools must be available from the command line (i.e. in the search path).\n#\n# The result: instead of the source browser generated by doxygen, the links to\n# source code will now point to the output of htags.\n# The default value is: NO.\n# This tag requires that the tag SOURCE_BROWSER is set to YES.\n\nUSE_HTAGS              = NO\n\n# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a\n# verbatim copy of the header file for each class for which an include is\n# specified. Set to NO to disable this.\n# See also: Section \\class.\n# The default value is: YES.\n\nVERBATIM_HEADERS       = YES\n\n#---------------------------------------------------------------------------\n# Configuration options related to the alphabetical class index\n#---------------------------------------------------------------------------\n\n# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all\n# compounds will be generated. Enable this if the project contains a lot of\n# classes, structs, unions or interfaces.\n# The default value is: YES.\n\nALPHABETICAL_INDEX     = YES\n\n# The IGNORE_PREFIX tag can be used to specify a prefix (or a list of prefixes)\n# that should be ignored while generating the index headers. The IGNORE_PREFIX\n# tag works for classes, function and member names. The entity will be placed in\n# the alphabetical list under the first letter of the entity name that remains\n# after removing the prefix.\n# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.\n\nIGNORE_PREFIX          =\n\n#---------------------------------------------------------------------------\n# Configuration options related to the HTML output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output\n# The default value is: YES.\n\nGENERATE_HTML          = YES\n\n# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a\n# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of\n# it.\n# The default directory is: html.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_OUTPUT            = html\n\n# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each\n# generated HTML page (for example: .htm, .php, .asp).\n# The default value is: .html.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_FILE_EXTENSION    = .html\n\n# The HTML_HEADER tag can be used to specify a user-defined HTML header file for\n# each generated HTML page. If the tag is left blank doxygen will generate a\n# standard header.\n#\n# To get valid HTML the header file that includes any scripts and style sheets\n# that doxygen needs, which is dependent on the configuration options used (e.g.\n# the setting GENERATE_TREEVIEW). It is highly recommended to start with a\n# default header using\n# doxygen -w html new_header.html new_footer.html new_stylesheet.css\n# YourConfigFile\n# and then modify the file new_header.html. See also section \"Doxygen usage\"\n# for information on how to generate the default header that doxygen normally\n# uses.\n# Note: The header is subject to change so you typically have to regenerate the\n# default header when upgrading to a newer version of doxygen. For a description\n# of the possible markers and block names see the documentation.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_HEADER            =\n\n# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each\n# generated HTML page. If the tag is left blank doxygen will generate a standard\n# footer. See HTML_HEADER for more information on how to generate a default\n# footer and what special commands can be used inside the footer. See also\n# section \"Doxygen usage\" for information on how to generate the default footer\n# that doxygen normally uses.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_FOOTER            =\n\n# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style\n# sheet that is used by each HTML page. It can be used to fine-tune the look of\n# the HTML output. If left blank doxygen will generate a default style sheet.\n# See also section \"Doxygen usage\" for information on how to generate the style\n# sheet that doxygen normally uses.\n# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as\n# it is more robust and this tag (HTML_STYLESHEET) will in the future become\n# obsolete.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_STYLESHEET        = ./documentation/customdoxygen.css\n\n# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined\n# cascading style sheets that are included after the standard style sheets\n# created by doxygen. Using this option one can overrule certain style aspects.\n# This is preferred over using HTML_STYLESHEET since it does not replace the\n# standard style sheet and is therefore more robust against future updates.\n# Doxygen will copy the style sheet files to the output directory.\n# Note: The order of the extra style sheet files is of importance (e.g. the last\n# style sheet in the list overrules the setting of the previous ones in the\n# list).\n# Note: Since the styling of scrollbars can currently not be overruled in\n# Webkit/Chromium, the styling will be left out of the default doxygen.css if\n# one or more extra stylesheets have been specified. So if scrollbar\n# customization is desired it has to be added explicitly. For an example see the\n# documentation.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_EXTRA_STYLESHEET  =\n\n# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or\n# other source files which should be copied to the HTML output directory. Note\n# that these files will be copied to the base HTML output directory. Use the\n# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these\n# files. In the HTML_STYLESHEET file, use the file name only. Also note that the\n# files will be copied as-is; there are no commands or markers available.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_EXTRA_FILES       =\n\n# The HTML_COLORSTYLE tag can be used to specify if the generated HTML output\n# should be rendered with a dark or light theme.\n# Possible values are: LIGHT always generate light mode output, DARK always\n# generate dark mode output, AUTO_LIGHT automatically set the mode according to\n# the user preference, use light mode if no preference is set (the default),\n# AUTO_DARK automatically set the mode according to the user preference, use\n# dark mode if no preference is set and TOGGLE allow to user to switch between\n# light and dark mode via a button.\n# The default value is: AUTO_LIGHT.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_COLORSTYLE        = AUTO_LIGHT\n\n# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen\n# will adjust the colors in the style sheet and background images according to\n# this color. Hue is specified as an angle on a color-wheel, see\n# https://en.wikipedia.org/wiki/Hue for more information. For instance the value\n# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300\n# purple, and 360 is red again.\n# Minimum value: 0, maximum value: 359, default value: 220.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_COLORSTYLE_HUE    = 220\n\n# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors\n# in the HTML output. For a value of 0 the output will use gray-scales only. A\n# value of 255 will produce the most vivid colors.\n# Minimum value: 0, maximum value: 255, default value: 100.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_COLORSTYLE_SAT    = 100\n\n# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the\n# luminance component of the colors in the HTML output. Values below 100\n# gradually make the output lighter, whereas values above 100 make the output\n# darker. The value divided by 100 is the actual gamma applied, so 80 represents\n# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not\n# change the gamma.\n# Minimum value: 40, maximum value: 240, default value: 80.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_COLORSTYLE_GAMMA  = 80\n\n# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML\n# page will contain the date and time when the page was generated. Setting this\n# to YES can help to show when doxygen was last run and thus if the\n# documentation is up to date.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_TIMESTAMP         = YES\n\n# If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML\n# documentation will contain a main index with vertical navigation menus that\n# are dynamically created via JavaScript. If disabled, the navigation index will\n# consists of multiple levels of tabs that are statically embedded in every HTML\n# page. Disable this option to support browsers that do not have JavaScript,\n# like the Qt help browser.\n# The default value is: YES.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_DYNAMIC_MENUS     = YES\n\n# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML\n# documentation will contain sections that can be hidden and shown after the\n# page has loaded.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_DYNAMIC_SECTIONS  = NO\n\n# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries\n# shown in the various tree structured indices initially; the user can expand\n# and collapse entries dynamically later on. Doxygen will expand the tree to\n# such a level that at most the specified number of entries are visible (unless\n# a fully collapsed tree already exceeds this amount). So setting the number of\n# entries 1 will produce a full collapsed tree by default. 0 is a special value\n# representing an infinite number of entries and will result in a full expanded\n# tree by default.\n# Minimum value: 0, maximum value: 9999, default value: 100.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_INDEX_NUM_ENTRIES = 100\n\n# If the GENERATE_DOCSET tag is set to YES, additional index files will be\n# generated that can be used as input for Apple's Xcode 3 integrated development\n# environment (see:\n# https://developer.apple.com/xcode/), introduced with OSX 10.5 (Leopard). To\n# create a documentation set, doxygen will generate a Makefile in the HTML\n# output directory. Running make will produce the docset in that directory and\n# running make install will install the docset in\n# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at\n# startup. See https://developer.apple.com/library/archive/featuredarticles/Doxy\n# genXcode/_index.html for more information.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nGENERATE_DOCSET        = NO\n\n# This tag determines the name of the docset feed. A documentation feed provides\n# an umbrella under which multiple documentation sets from a single provider\n# (such as a company or product suite) can be grouped.\n# The default value is: Doxygen generated docs.\n# This tag requires that the tag GENERATE_DOCSET is set to YES.\n\nDOCSET_FEEDNAME        = \"Doxygen generated docs\"\n\n# This tag determines the URL of the docset feed. A documentation feed provides\n# an umbrella under which multiple documentation sets from a single provider\n# (such as a company or product suite) can be grouped.\n# This tag requires that the tag GENERATE_DOCSET is set to YES.\n\nDOCSET_FEEDURL         =\n\n# This tag specifies a string that should uniquely identify the documentation\n# set bundle. This should be a reverse domain-name style string, e.g.\n# com.mycompany.MyDocSet. Doxygen will append .docset to the name.\n# The default value is: org.doxygen.Project.\n# This tag requires that the tag GENERATE_DOCSET is set to YES.\n\nDOCSET_BUNDLE_ID       = org.doxygen.Project\n\n# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify\n# the documentation publisher. This should be a reverse domain-name style\n# string, e.g. com.mycompany.MyDocSet.documentation.\n# The default value is: org.doxygen.Publisher.\n# This tag requires that the tag GENERATE_DOCSET is set to YES.\n\nDOCSET_PUBLISHER_ID    = org.doxygen.Publisher\n\n# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.\n# The default value is: Publisher.\n# This tag requires that the tag GENERATE_DOCSET is set to YES.\n\nDOCSET_PUBLISHER_NAME  = Publisher\n\n# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three\n# additional HTML index files: index.hhp, index.hhc, and index.hhk. The\n# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop\n# on Windows. In the beginning of 2021 Microsoft took the original page, with\n# a.o. the download links, offline the HTML help workshop was already many years\n# in maintenance mode). You can download the HTML help workshop from the web\n# archives at Installation executable (see:\n# http://web.archive.org/web/20160201063255/http://download.microsoft.com/downlo\n# ad/0/A/9/0A939EF6-E31C-430F-A3DF-DFAE7960D564/htmlhelp.exe).\n#\n# The HTML Help Workshop contains a compiler that can convert all HTML output\n# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML\n# files are now used as the Windows 98 help format, and will replace the old\n# Windows help format (.hlp) on all Windows platforms in the future. Compressed\n# HTML files also contain an index, a table of contents, and you can search for\n# words in the documentation. The HTML workshop also contains a viewer for\n# compressed HTML files.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nGENERATE_HTMLHELP      = NO\n\n# The CHM_FILE tag can be used to specify the file name of the resulting .chm\n# file. You can add a path in front of the file if the result should not be\n# written to the html output directory.\n# This tag requires that the tag GENERATE_HTMLHELP is set to YES.\n\nCHM_FILE               =\n\n# The HHC_LOCATION tag can be used to specify the location (absolute path\n# including file name) of the HTML help compiler (hhc.exe). If non-empty,\n# doxygen will try to run the HTML help compiler on the generated index.hhp.\n# The file has to be specified with full path.\n# This tag requires that the tag GENERATE_HTMLHELP is set to YES.\n\nHHC_LOCATION           =\n\n# The GENERATE_CHI flag controls if a separate .chi index file is generated\n# (YES) or that it should be included in the main .chm file (NO).\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTMLHELP is set to YES.\n\nGENERATE_CHI           = NO\n\n# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc)\n# and project file content.\n# This tag requires that the tag GENERATE_HTMLHELP is set to YES.\n\nCHM_INDEX_ENCODING     =\n\n# The BINARY_TOC flag controls whether a binary table of contents is generated\n# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it\n# enables the Previous and Next buttons.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTMLHELP is set to YES.\n\nBINARY_TOC             = NO\n\n# The TOC_EXPAND flag can be set to YES to add extra items for group members to\n# the table of contents of the HTML help documentation and to the tree view.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTMLHELP is set to YES.\n\nTOC_EXPAND             = NO\n\n# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and\n# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that\n# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help\n# (.qch) of the generated HTML documentation.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nGENERATE_QHP           = NO\n\n# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify\n# the file name of the resulting .qch file. The path specified is relative to\n# the HTML output folder.\n# This tag requires that the tag GENERATE_QHP is set to YES.\n\nQCH_FILE               =\n\n# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help\n# Project output. For more information please see Qt Help Project / Namespace\n# (see:\n# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace).\n# The default value is: org.doxygen.Project.\n# This tag requires that the tag GENERATE_QHP is set to YES.\n\nQHP_NAMESPACE          = org.doxygen.Project\n\n# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt\n# Help Project output. For more information please see Qt Help Project / Virtual\n# Folders (see:\n# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual-folders).\n# The default value is: doc.\n# This tag requires that the tag GENERATE_QHP is set to YES.\n\nQHP_VIRTUAL_FOLDER     = doc\n\n# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom\n# filter to add. For more information please see Qt Help Project / Custom\n# Filters (see:\n# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters).\n# This tag requires that the tag GENERATE_QHP is set to YES.\n\nQHP_CUST_FILTER_NAME   =\n\n# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the\n# custom filter to add. For more information please see Qt Help Project / Custom\n# Filters (see:\n# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters).\n# This tag requires that the tag GENERATE_QHP is set to YES.\n\nQHP_CUST_FILTER_ATTRS  =\n\n# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this\n# project's filter section matches. Qt Help Project / Filter Attributes (see:\n# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#filter-attributes).\n# This tag requires that the tag GENERATE_QHP is set to YES.\n\nQHP_SECT_FILTER_ATTRS  =\n\n# The QHG_LOCATION tag can be used to specify the location (absolute path\n# including file name) of Qt's qhelpgenerator. If non-empty doxygen will try to\n# run qhelpgenerator on the generated .qhp file.\n# This tag requires that the tag GENERATE_QHP is set to YES.\n\nQHG_LOCATION           =\n\n# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be\n# generated, together with the HTML files, they form an Eclipse help plugin. To\n# install this plugin and make it available under the help contents menu in\n# Eclipse, the contents of the directory containing the HTML and XML files needs\n# to be copied into the plugins directory of eclipse. The name of the directory\n# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.\n# After copying Eclipse needs to be restarted before the help appears.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nGENERATE_ECLIPSEHELP   = NO\n\n# A unique identifier for the Eclipse help plugin. When installing the plugin\n# the directory name containing the HTML and XML files should also have this\n# name. Each documentation set should have its own identifier.\n# The default value is: org.doxygen.Project.\n# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.\n\nECLIPSE_DOC_ID         = org.doxygen.Project\n\n# If you want full control over the layout of the generated HTML pages it might\n# be necessary to disable the index and replace it with your own. The\n# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top\n# of each HTML page. A value of NO enables the index and the value YES disables\n# it. Since the tabs in the index contain the same information as the navigation\n# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nDISABLE_INDEX          = NO\n\n# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index\n# structure should be generated to display hierarchical information. If the tag\n# value is set to YES, a side panel will be generated containing a tree-like\n# index structure (just like the one that is generated for HTML Help). For this\n# to work a browser that supports JavaScript, DHTML, CSS and frames is required\n# (i.e. any modern browser). Windows users are probably better off using the\n# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can\n# further fine tune the look of the index (see \"Fine-tuning the output\"). As an\n# example, the default style sheet generated by doxygen has an example that\n# shows how to put an image at the root of the tree instead of the PROJECT_NAME.\n# Since the tree basically has the same information as the tab index, you could\n# consider setting DISABLE_INDEX to YES when enabling this option.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nGENERATE_TREEVIEW      = NO\n\n# When both GENERATE_TREEVIEW and DISABLE_INDEX are set to YES, then the\n# FULL_SIDEBAR option determines if the side bar is limited to only the treeview\n# area (value NO) or if it should extend to the full height of the window (value\n# YES). Setting this to YES gives a layout similar to\n# https://docs.readthedocs.io with more room for contents, but less room for the\n# project logo, title, and description. If either GENERATE_TREEVIEW or\n# DISABLE_INDEX is set to NO, this option has no effect.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nFULL_SIDEBAR           = NO\n\n# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that\n# doxygen will group on one line in the generated HTML documentation.\n#\n# Note that a value of 0 will completely suppress the enum values from appearing\n# in the overview section.\n# Minimum value: 0, maximum value: 20, default value: 4.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nENUM_VALUES_PER_LINE   = 4\n\n# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used\n# to set the initial width (in pixels) of the frame in which the tree is shown.\n# Minimum value: 0, maximum value: 1500, default value: 250.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nTREEVIEW_WIDTH         = 250\n\n# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to\n# external symbols imported via tag files in a separate window.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nEXT_LINKS_IN_WINDOW    = NO\n\n# If the OBFUSCATE_EMAILS tag is set to YES, doxygen will obfuscate email\n# addresses.\n# The default value is: YES.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nOBFUSCATE_EMAILS       = YES\n\n# If the HTML_FORMULA_FORMAT option is set to svg, doxygen will use the pdf2svg\n# tool (see https://github.com/dawbarton/pdf2svg) or inkscape (see\n# https://inkscape.org) to generate formulas as SVG images instead of PNGs for\n# the HTML output. These images will generally look nicer at scaled resolutions.\n# Possible values are: png (the default) and svg (looks nicer but requires the\n# pdf2svg or inkscape tool).\n# The default value is: png.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_FORMULA_FORMAT    = png\n\n# Use this tag to change the font size of LaTeX formulas included as images in\n# the HTML documentation. When you change the font size after a successful\n# doxygen run you need to manually remove any form_*.png images from the HTML\n# output directory to force them to be regenerated.\n# Minimum value: 8, maximum value: 50, default value: 10.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nFORMULA_FONTSIZE       = 10\n\n# The FORMULA_MACROFILE can contain LaTeX \\newcommand and \\renewcommand commands\n# to create new LaTeX commands to be used in formulas as building blocks. See\n# the section \"Including formulas\" for details.\n\nFORMULA_MACROFILE      =\n\n# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see\n# https://www.mathjax.org) which uses client side JavaScript for the rendering\n# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX\n# installed or if you want to formulas look prettier in the HTML output. When\n# enabled you may also need to install MathJax separately and configure the path\n# to it using the MATHJAX_RELPATH option.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nUSE_MATHJAX            = NO\n\n# With MATHJAX_VERSION it is possible to specify the MathJax version to be used.\n# Note that the different versions of MathJax have different requirements with\n# regards to the different settings, so it is possible that also other MathJax\n# settings have to be changed when switching between the different MathJax\n# versions.\n# Possible values are: MathJax_2 and MathJax_3.\n# The default value is: MathJax_2.\n# This tag requires that the tag USE_MATHJAX is set to YES.\n\nMATHJAX_VERSION        = MathJax_2\n\n# When MathJax is enabled you can set the default output format to be used for\n# the MathJax output. For more details about the output format see MathJax\n# version 2 (see:\n# http://docs.mathjax.org/en/v2.7-latest/output.html) and MathJax version 3\n# (see:\n# http://docs.mathjax.org/en/latest/web/components/output.html).\n# Possible values are: HTML-CSS (which is slower, but has the best\n# compatibility. This is the name for Mathjax version 2, for MathJax version 3\n# this will be translated into chtml), NativeMML (i.e. MathML. Only supported\n# for NathJax 2. For MathJax version 3 chtml will be used instead.), chtml (This\n# is the name for Mathjax version 3, for MathJax version 2 this will be\n# translated into HTML-CSS) and SVG.\n# The default value is: HTML-CSS.\n# This tag requires that the tag USE_MATHJAX is set to YES.\n\nMATHJAX_FORMAT         = HTML-CSS\n\n# When MathJax is enabled you need to specify the location relative to the HTML\n# output directory using the MATHJAX_RELPATH option. The destination directory\n# should contain the MathJax.js script. For instance, if the mathjax directory\n# is located at the same level as the HTML output directory, then\n# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax\n# Content Delivery Network so you can quickly see the result without installing\n# MathJax. However, it is strongly recommended to install a local copy of\n# MathJax from https://www.mathjax.org before deployment. The default value is:\n# - in case of MathJax version 2: https://cdn.jsdelivr.net/npm/mathjax@2\n# - in case of MathJax version 3: https://cdn.jsdelivr.net/npm/mathjax@3\n# This tag requires that the tag USE_MATHJAX is set to YES.\n\nMATHJAX_RELPATH        = http://cdn.mathjax.org/mathjax/latest\n\n# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax\n# extension names that should be enabled during MathJax rendering. For example\n# for MathJax version 2 (see\n# https://docs.mathjax.org/en/v2.7-latest/tex.html#tex-and-latex-extensions):\n# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols\n# For example for MathJax version 3 (see\n# http://docs.mathjax.org/en/latest/input/tex/extensions/index.html):\n# MATHJAX_EXTENSIONS = ams\n# This tag requires that the tag USE_MATHJAX is set to YES.\n\nMATHJAX_EXTENSIONS     =\n\n# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces\n# of code that will be used on startup of the MathJax code. See the MathJax site\n# (see:\n# http://docs.mathjax.org/en/v2.7-latest/output.html) for more details. For an\n# example see the documentation.\n# This tag requires that the tag USE_MATHJAX is set to YES.\n\nMATHJAX_CODEFILE       =\n\n# When the SEARCHENGINE tag is enabled doxygen will generate a search box for\n# the HTML output. The underlying search engine uses javascript and DHTML and\n# should work on any modern browser. Note that when using HTML help\n# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)\n# there is already a search function so this one should typically be disabled.\n# For large projects the javascript based search engine can be slow, then\n# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to\n# search using the keyboard; to jump to the search box use <access key> + S\n# (what the <access key> is depends on the OS and browser, but it is typically\n# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down\n# key> to jump into the search results window, the results can be navigated\n# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel\n# the search. The filter options can be selected when the cursor is inside the\n# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>\n# to select a filter and <Enter> or <escape> to activate or cancel the filter\n# option.\n# The default value is: YES.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nSEARCHENGINE           = YES\n\n# When the SERVER_BASED_SEARCH tag is enabled the search engine will be\n# implemented using a web server instead of a web client using JavaScript. There\n# are two flavors of web server based searching depending on the EXTERNAL_SEARCH\n# setting. When disabled, doxygen will generate a PHP script for searching and\n# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing\n# and searching needs to be provided by external tools. See the section\n# \"External Indexing and Searching\" for details.\n# The default value is: NO.\n# This tag requires that the tag SEARCHENGINE is set to YES.\n\nSERVER_BASED_SEARCH    = NO\n\n# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP\n# script for searching. Instead the search results are written to an XML file\n# which needs to be processed by an external indexer. Doxygen will invoke an\n# external search engine pointed to by the SEARCHENGINE_URL option to obtain the\n# search results.\n#\n# Doxygen ships with an example indexer (doxyindexer) and search engine\n# (doxysearch.cgi) which are based on the open source search engine library\n# Xapian (see:\n# https://xapian.org/).\n#\n# See the section \"External Indexing and Searching\" for details.\n# The default value is: NO.\n# This tag requires that the tag SEARCHENGINE is set to YES.\n\nEXTERNAL_SEARCH        = NO\n\n# The SEARCHENGINE_URL should point to a search engine hosted by a web server\n# which will return the search results when EXTERNAL_SEARCH is enabled.\n#\n# Doxygen ships with an example indexer (doxyindexer) and search engine\n# (doxysearch.cgi) which are based on the open source search engine library\n# Xapian (see:\n# https://xapian.org/). See the section \"External Indexing and Searching\" for\n# details.\n# This tag requires that the tag SEARCHENGINE is set to YES.\n\nSEARCHENGINE_URL       =\n\n# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed\n# search data is written to a file for indexing by an external tool. With the\n# SEARCHDATA_FILE tag the name of this file can be specified.\n# The default file is: searchdata.xml.\n# This tag requires that the tag SEARCHENGINE is set to YES.\n\nSEARCHDATA_FILE        = searchdata.xml\n\n# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the\n# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is\n# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple\n# projects and redirect the results back to the right project.\n# This tag requires that the tag SEARCHENGINE is set to YES.\n\nEXTERNAL_SEARCH_ID     =\n\n# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen\n# projects other than the one defined by this configuration file, but that are\n# all added to the same external search index. Each project needs to have a\n# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of\n# to a relative location where the documentation can be found. The format is:\n# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...\n# This tag requires that the tag SEARCHENGINE is set to YES.\n\nEXTRA_SEARCH_MAPPINGS  =\n\n#---------------------------------------------------------------------------\n# Configuration options related to the LaTeX output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output.\n# The default value is: YES.\n\nGENERATE_LATEX         = NO\n\n# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a\n# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of\n# it.\n# The default directory is: latex.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nLATEX_OUTPUT           = latex\n\n# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be\n# invoked.\n#\n# Note that when not enabling USE_PDFLATEX the default is latex when enabling\n# USE_PDFLATEX the default is pdflatex and when in the later case latex is\n# chosen this is overwritten by pdflatex. For specific output languages the\n# default can have been set differently, this depends on the implementation of\n# the output language.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nLATEX_CMD_NAME         = latex\n\n# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate\n# index for LaTeX.\n# Note: This tag is used in the Makefile / make.bat.\n# See also: LATEX_MAKEINDEX_CMD for the part in the generated output file\n# (.tex).\n# The default file is: makeindex.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nMAKEINDEX_CMD_NAME     = makeindex\n\n# The LATEX_MAKEINDEX_CMD tag can be used to specify the command name to\n# generate index for LaTeX. In case there is no backslash (\\) as first character\n# it will be automatically added in the LaTeX code.\n# Note: This tag is used in the generated output file (.tex).\n# See also: MAKEINDEX_CMD_NAME for the part in the Makefile / make.bat.\n# The default value is: makeindex.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nLATEX_MAKEINDEX_CMD    = makeindex\n\n# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX\n# documents. This may be useful for small projects and may help to save some\n# trees in general.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nCOMPACT_LATEX          = NO\n\n# The PAPER_TYPE tag can be used to set the paper type that is used by the\n# printer.\n# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x\n# 14 inches) and executive (7.25 x 10.5 inches).\n# The default value is: a4.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nPAPER_TYPE             = a4\n\n# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names\n# that should be included in the LaTeX output. The package can be specified just\n# by its name or with the correct syntax as to be used with the LaTeX\n# \\usepackage command. To get the times font for instance you can specify :\n# EXTRA_PACKAGES=times or EXTRA_PACKAGES={times}\n# To use the option intlimits with the amsmath package you can specify:\n# EXTRA_PACKAGES=[intlimits]{amsmath}\n# If left blank no extra packages will be included.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nEXTRA_PACKAGES         =\n\n# The LATEX_HEADER tag can be used to specify a user-defined LaTeX header for\n# the generated LaTeX document. The header should contain everything until the\n# first chapter. If it is left blank doxygen will generate a standard header. It\n# is highly recommended to start with a default header using\n# doxygen -w latex new_header.tex new_footer.tex new_stylesheet.sty\n# and then modify the file new_header.tex. See also section \"Doxygen usage\" for\n# information on how to generate the default header that doxygen normally uses.\n#\n# Note: Only use a user-defined header if you know what you are doing!\n# Note: The header is subject to change so you typically have to regenerate the\n# default header when upgrading to a newer version of doxygen. The following\n# commands have a special meaning inside the header (and footer): For a\n# description of the possible markers and block names see the documentation.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nLATEX_HEADER           =\n\n# The LATEX_FOOTER tag can be used to specify a user-defined LaTeX footer for\n# the generated LaTeX document. The footer should contain everything after the\n# last chapter. If it is left blank doxygen will generate a standard footer. See\n# LATEX_HEADER for more information on how to generate a default footer and what\n# special commands can be used inside the footer. See also section \"Doxygen\n# usage\" for information on how to generate the default footer that doxygen\n# normally uses. Note: Only use a user-defined footer if you know what you are\n# doing!\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nLATEX_FOOTER           =\n\n# The LATEX_EXTRA_STYLESHEET tag can be used to specify additional user-defined\n# LaTeX style sheets that are included after the standard style sheets created\n# by doxygen. Using this option one can overrule certain style aspects. Doxygen\n# will copy the style sheet files to the output directory.\n# Note: The order of the extra style sheet files is of importance (e.g. the last\n# style sheet in the list overrules the setting of the previous ones in the\n# list).\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nLATEX_EXTRA_STYLESHEET =\n\n# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or\n# other source files which should be copied to the LATEX_OUTPUT output\n# directory. Note that the files will be copied as-is; there are no commands or\n# markers available.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nLATEX_EXTRA_FILES      =\n\n# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is\n# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will\n# contain links (just like the HTML output) instead of page references. This\n# makes the output suitable for online browsing using a PDF viewer.\n# The default value is: YES.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nPDF_HYPERLINKS         = YES\n\n# If the USE_PDFLATEX tag is set to YES, doxygen will use the engine as\n# specified with LATEX_CMD_NAME to generate the PDF file directly from the LaTeX\n# files. Set this option to YES, to get a higher quality PDF documentation.\n#\n# See also section LATEX_CMD_NAME for selecting the engine.\n# The default value is: YES.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nUSE_PDFLATEX           = YES\n\n# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode\n# command to the generated LaTeX files. This will instruct LaTeX to keep running\n# if errors occur, instead of asking the user for help.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nLATEX_BATCHMODE        = NO\n\n# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the\n# index chapters (such as File Index, Compound Index, etc.) in the output.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nLATEX_HIDE_INDICES     = NO\n\n# The LATEX_BIB_STYLE tag can be used to specify the style to use for the\n# bibliography, e.g. plainnat, or ieeetr. See\n# https://en.wikipedia.org/wiki/BibTeX and \\cite for more info.\n# The default value is: plain.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nLATEX_BIB_STYLE        = plain\n\n# If the LATEX_TIMESTAMP tag is set to YES then the footer of each generated\n# page will contain the date and time when the page was generated. Setting this\n# to NO can help when comparing the output of multiple runs.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nLATEX_TIMESTAMP        = NO\n\n# The LATEX_EMOJI_DIRECTORY tag is used to specify the (relative or absolute)\n# path from which the emoji images will be read. If a relative path is entered,\n# it will be relative to the LATEX_OUTPUT directory. If left blank the\n# LATEX_OUTPUT directory will be used.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nLATEX_EMOJI_DIRECTORY  =\n\n#---------------------------------------------------------------------------\n# Configuration options related to the RTF output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The\n# RTF output is optimized for Word 97 and may not look too pretty with other RTF\n# readers/editors.\n# The default value is: NO.\n\nGENERATE_RTF           = NO\n\n# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a\n# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of\n# it.\n# The default directory is: rtf.\n# This tag requires that the tag GENERATE_RTF is set to YES.\n\nRTF_OUTPUT             = rtf\n\n# If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF\n# documents. This may be useful for small projects and may help to save some\n# trees in general.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_RTF is set to YES.\n\nCOMPACT_RTF            = NO\n\n# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will\n# contain hyperlink fields. The RTF file will contain links (just like the HTML\n# output) instead of page references. This makes the output suitable for online\n# browsing using Word or some other Word compatible readers that support those\n# fields.\n#\n# Note: WordPad (write) and others do not support links.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_RTF is set to YES.\n\nRTF_HYPERLINKS         = NO\n\n# Load stylesheet definitions from file. Syntax is similar to doxygen's\n# configuration file, i.e. a series of assignments. You only have to provide\n# replacements, missing definitions are set to their default value.\n#\n# See also section \"Doxygen usage\" for information on how to generate the\n# default style sheet that doxygen normally uses.\n# This tag requires that the tag GENERATE_RTF is set to YES.\n\nRTF_STYLESHEET_FILE    =\n\n# Set optional variables used in the generation of an RTF document. Syntax is\n# similar to doxygen's configuration file. A template extensions file can be\n# generated using doxygen -e rtf extensionFile.\n# This tag requires that the tag GENERATE_RTF is set to YES.\n\nRTF_EXTENSIONS_FILE    =\n\n#---------------------------------------------------------------------------\n# Configuration options related to the man page output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for\n# classes and files.\n# The default value is: NO.\n\nGENERATE_MAN           = NO\n\n# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a\n# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of\n# it. A directory man3 will be created inside the directory specified by\n# MAN_OUTPUT.\n# The default directory is: man.\n# This tag requires that the tag GENERATE_MAN is set to YES.\n\nMAN_OUTPUT             = man\n\n# The MAN_EXTENSION tag determines the extension that is added to the generated\n# man pages. In case the manual section does not start with a number, the number\n# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is\n# optional.\n# The default value is: .3.\n# This tag requires that the tag GENERATE_MAN is set to YES.\n\nMAN_EXTENSION          = .3\n\n# The MAN_SUBDIR tag determines the name of the directory created within\n# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by\n# MAN_EXTENSION with the initial . removed.\n# This tag requires that the tag GENERATE_MAN is set to YES.\n\nMAN_SUBDIR             =\n\n# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it\n# will generate one additional man file for each entity documented in the real\n# man page(s). These additional files only source the real man page, but without\n# them the man command would be unable to find the correct page.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_MAN is set to YES.\n\nMAN_LINKS              = NO\n\n#---------------------------------------------------------------------------\n# Configuration options related to the XML output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that\n# captures the structure of the code including all documentation.\n# The default value is: NO.\n\nGENERATE_XML           = NO\n\n# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a\n# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of\n# it.\n# The default directory is: xml.\n# This tag requires that the tag GENERATE_XML is set to YES.\n\nXML_OUTPUT             = xml\n\n# If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program\n# listings (including syntax highlighting and cross-referencing information) to\n# the XML output. Note that enabling this will significantly increase the size\n# of the XML output.\n# The default value is: YES.\n# This tag requires that the tag GENERATE_XML is set to YES.\n\nXML_PROGRAMLISTING     = YES\n\n# If the XML_NS_MEMB_FILE_SCOPE tag is set to YES, doxygen will include\n# namespace members in file scope as well, matching the HTML output.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_XML is set to YES.\n\nXML_NS_MEMB_FILE_SCOPE = NO\n\n#---------------------------------------------------------------------------\n# Configuration options related to the DOCBOOK output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_DOCBOOK tag is set to YES, doxygen will generate Docbook files\n# that can be used to generate PDF.\n# The default value is: NO.\n\nGENERATE_DOCBOOK       = NO\n\n# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.\n# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in\n# front of it.\n# The default directory is: docbook.\n# This tag requires that the tag GENERATE_DOCBOOK is set to YES.\n\nDOCBOOK_OUTPUT         = docbook\n\n#---------------------------------------------------------------------------\n# Configuration options for the AutoGen Definitions output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an\n# AutoGen Definitions (see http://autogen.sourceforge.net/) file that captures\n# the structure of the code including all documentation. Note that this feature\n# is still experimental and incomplete at the moment.\n# The default value is: NO.\n\nGENERATE_AUTOGEN_DEF   = NO\n\n#---------------------------------------------------------------------------\n# Configuration options related to the Perl module output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_PERLMOD tag is set to YES, doxygen will generate a Perl module\n# file that captures the structure of the code including all documentation.\n#\n# Note that this feature is still experimental and incomplete at the moment.\n# The default value is: NO.\n\nGENERATE_PERLMOD       = NO\n\n# If the PERLMOD_LATEX tag is set to YES, doxygen will generate the necessary\n# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI\n# output from the Perl module output.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_PERLMOD is set to YES.\n\nPERLMOD_LATEX          = NO\n\n# If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely\n# formatted so it can be parsed by a human reader. This is useful if you want to\n# understand what is going on. On the other hand, if this tag is set to NO, the\n# size of the Perl module output will be much smaller and Perl will parse it\n# just the same.\n# The default value is: YES.\n# This tag requires that the tag GENERATE_PERLMOD is set to YES.\n\nPERLMOD_PRETTY         = YES\n\n# The names of the make variables in the generated doxyrules.make file are\n# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful\n# so different doxyrules.make files included by the same Makefile don't\n# overwrite each other's variables.\n# This tag requires that the tag GENERATE_PERLMOD is set to YES.\n\nPERLMOD_MAKEVAR_PREFIX =\n\n#---------------------------------------------------------------------------\n# Configuration options related to the preprocessor\n#---------------------------------------------------------------------------\n\n# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all\n# C-preprocessor directives found in the sources and include files.\n# The default value is: YES.\n\nENABLE_PREPROCESSING   = YES\n\n# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names\n# in the source code. If set to NO, only conditional compilation will be\n# performed. Macro expansion can be done in a controlled way by setting\n# EXPAND_ONLY_PREDEF to YES.\n# The default value is: NO.\n# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.\n\nMACRO_EXPANSION        = NO\n\n# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then\n# the macro expansion is limited to the macros specified with the PREDEFINED and\n# EXPAND_AS_DEFINED tags.\n# The default value is: NO.\n# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.\n\nEXPAND_ONLY_PREDEF     = NO\n\n# If the SEARCH_INCLUDES tag is set to YES, the include files in the\n# INCLUDE_PATH will be searched if a #include is found.\n# The default value is: YES.\n# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.\n\nSEARCH_INCLUDES        = YES\n\n# The INCLUDE_PATH tag can be used to specify one or more directories that\n# contain include files that are not input files but should be processed by the\n# preprocessor. Note that the INCLUDE_PATH is not recursive, so the setting of\n# RECURSIVE has no effect here.\n# This tag requires that the tag SEARCH_INCLUDES is set to YES.\n\nINCLUDE_PATH           =\n\n# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard\n# patterns (like *.h and *.hpp) to filter out the header-files in the\n# directories. If left blank, the patterns specified with FILE_PATTERNS will be\n# used.\n# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.\n\nINCLUDE_FILE_PATTERNS  =\n\n# The PREDEFINED tag can be used to specify one or more macro names that are\n# defined before the preprocessor is started (similar to the -D option of e.g.\n# gcc). The argument of the tag is a list of macros of the form: name or\n# name=definition (no spaces). If the definition and the \"=\" are omitted, \"=1\"\n# is assumed. To prevent a macro definition from being undefined via #undef or\n# recursively expanded use the := operator instead of the = operator.\n# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.\n\nPREDEFINED             =\n\n# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this\n# tag can be used to specify a list of macro names that should be expanded. The\n# macro definition that is found in the sources will be used. Use the PREDEFINED\n# tag if you want to use a different macro definition that overrules the\n# definition found in the source code.\n# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.\n\nEXPAND_AS_DEFINED      =\n\n# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will\n# remove all references to function-like macros that are alone on a line, have\n# an all uppercase name, and do not end with a semicolon. Such function macros\n# are typically used for boiler-plate code, and will confuse the parser if not\n# removed.\n# The default value is: YES.\n# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.\n\nSKIP_FUNCTION_MACROS   = YES\n\n#---------------------------------------------------------------------------\n# Configuration options related to external references\n#---------------------------------------------------------------------------\n\n# The TAGFILES tag can be used to specify one or more tag files. For each tag\n# file the location of the external documentation should be added. The format of\n# a tag file without this location is as follows:\n# TAGFILES = file1 file2 ...\n# Adding location for the tag files is done as follows:\n# TAGFILES = file1=loc1 \"file2 = loc2\" ...\n# where loc1 and loc2 can be relative or absolute paths or URLs. See the\n# section \"Linking to external documentation\" for more information about the use\n# of tag files.\n# Note: Each tag file must have a unique name (where the name does NOT include\n# the path). If a tag file is not located in the directory in which doxygen is\n# run, you must also specify the path to the tagfile here.\n\nTAGFILES               =\n\n# When a file name is specified after GENERATE_TAGFILE, doxygen will create a\n# tag file that is based on the input files it reads. See section \"Linking to\n# external documentation\" for more information about the usage of tag files.\n\nGENERATE_TAGFILE       =\n\n# If the ALLEXTERNALS tag is set to YES, all external class will be listed in\n# the class index. If set to NO, only the inherited external classes will be\n# listed.\n# The default value is: NO.\n\nALLEXTERNALS           = NO\n\n# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed\n# in the modules index. If set to NO, only the current project's groups will be\n# listed.\n# The default value is: YES.\n\nEXTERNAL_GROUPS        = YES\n\n# If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in\n# the related pages index. If set to NO, only the current project's pages will\n# be listed.\n# The default value is: YES.\n\nEXTERNAL_PAGES         = YES\n\n#---------------------------------------------------------------------------\n# Configuration options related to the dot tool\n#---------------------------------------------------------------------------\n\n# You can include diagrams made with dia in doxygen documentation. Doxygen will\n# then run dia to produce the diagram and insert it in the documentation. The\n# DIA_PATH tag allows you to specify the directory where the dia binary resides.\n# If left empty dia is assumed to be found in the default search path.\n\nDIA_PATH               =\n\n# If set to YES the inheritance and collaboration graphs will hide inheritance\n# and usage relations if the target is undocumented or is not a class.\n# The default value is: YES.\n\nHIDE_UNDOC_RELATIONS   = YES\n\n# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is\n# available from the path. This tool is part of Graphviz (see:\n# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent\n# Bell Labs. The other options in this section have no effect if this option is\n# set to NO\n# The default value is: NO.\n\nHAVE_DOT               = NO\n\n# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed\n# to run in parallel. When set to 0 doxygen will base this on the number of\n# processors available in the system. You can set it explicitly to a value\n# larger than 0 to get control over the balance between CPU load and processing\n# speed.\n# Minimum value: 0, maximum value: 32, default value: 0.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nDOT_NUM_THREADS        = 0\n\n# DOT_COMMON_ATTR is common attributes for nodes, edges and labels of\n# subgraphs. When you want a differently looking font in the dot files that\n# doxygen generates you can specify fontname, fontcolor and fontsize attributes.\n# For details please see <a href=https://graphviz.org/doc/info/attrs.html>Node,\n# Edge and Graph Attributes specification</a> You need to make sure dot is able\n# to find the font, which can be done by putting it in a standard location or by\n# setting the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the\n# directory containing the font. Default graphviz fontsize is 14.\n# The default value is: fontname=Helvetica,fontsize=10.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nDOT_COMMON_ATTR        = \"fontname=Helvetica,fontsize=10\"\n\n# DOT_EDGE_ATTR is concatenated with DOT_COMMON_ATTR. For elegant style you can\n# add 'arrowhead=open, arrowtail=open, arrowsize=0.5'. <a\n# href=https://graphviz.org/doc/info/arrows.html>Complete documentation about\n# arrows shapes.</a>\n# The default value is: labelfontname=Helvetica,labelfontsize=10.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nDOT_EDGE_ATTR          = \"labelfontname=Helvetica,labelfontsize=10\"\n\n# DOT_NODE_ATTR is concatenated with DOT_COMMON_ATTR. For view without boxes\n# around nodes set 'shape=plain' or 'shape=plaintext' <a\n# href=https://www.graphviz.org/doc/info/shapes.html>Shapes specification</a>\n# The default value is: shape=box,height=0.2,width=0.4.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nDOT_NODE_ATTR          = \"shape=box,height=0.2,width=0.4\"\n\n# You can set the path where dot can find font specified with fontname in\n# DOT_COMMON_ATTR and others dot attributes.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nDOT_FONTPATH           =\n\n# If the CLASS_GRAPH tag is set to YES (or GRAPH) then doxygen will generate a\n# graph for each documented class showing the direct and indirect inheritance\n# relations. In case HAVE_DOT is set as well dot will be used to draw the graph,\n# otherwise the built-in generator will be used. If the CLASS_GRAPH tag is set\n# to TEXT the direct and indirect inheritance relations will be shown as texts /\n# links.\n# Possible values are: NO, YES, TEXT and GRAPH.\n# The default value is: YES.\n\nCLASS_GRAPH            = YES\n\n# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a\n# graph for each documented class showing the direct and indirect implementation\n# dependencies (inheritance, containment, and class references variables) of the\n# class with other documented classes.\n# The default value is: YES.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nCOLLABORATION_GRAPH    = YES\n\n# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for\n# groups, showing the direct groups dependencies. See also the chapter Grouping\n# in the manual.\n# The default value is: YES.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nGROUP_GRAPHS           = YES\n\n# If the UML_LOOK tag is set to YES, doxygen will generate inheritance and\n# collaboration diagrams in a style similar to the OMG's Unified Modeling\n# Language.\n# The default value is: NO.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nUML_LOOK               = NO\n\n# If the UML_LOOK tag is enabled, the fields and methods are shown inside the\n# class node. If there are many fields or methods and many nodes the graph may\n# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the\n# number of items for each type to make the size more manageable. Set this to 0\n# for no limit. Note that the threshold may be exceeded by 50% before the limit\n# is enforced. So when you set the threshold to 10, up to 15 fields may appear,\n# but if the number exceeds 15, the total amount of fields shown is limited to\n# 10.\n# Minimum value: 0, maximum value: 100, default value: 10.\n# This tag requires that the tag UML_LOOK is set to YES.\n\nUML_LIMIT_NUM_FIELDS   = 10\n\n# If the DOT_UML_DETAILS tag is set to NO, doxygen will show attributes and\n# methods without types and arguments in the UML graphs. If the DOT_UML_DETAILS\n# tag is set to YES, doxygen will add type and arguments for attributes and\n# methods in the UML graphs. If the DOT_UML_DETAILS tag is set to NONE, doxygen\n# will not generate fields with class member information in the UML graphs. The\n# class diagrams will look similar to the default class diagrams but using UML\n# notation for the relationships.\n# Possible values are: NO, YES and NONE.\n# The default value is: NO.\n# This tag requires that the tag UML_LOOK is set to YES.\n\nDOT_UML_DETAILS        = NO\n\n# The DOT_WRAP_THRESHOLD tag can be used to set the maximum number of characters\n# to display on a single line. If the actual line length exceeds this threshold\n# significantly it will wrapped across multiple lines. Some heuristics are apply\n# to avoid ugly line breaks.\n# Minimum value: 0, maximum value: 1000, default value: 17.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nDOT_WRAP_THRESHOLD     = 17\n\n# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and\n# collaboration graphs will show the relations between templates and their\n# instances.\n# The default value is: NO.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nTEMPLATE_RELATIONS     = NO\n\n# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to\n# YES then doxygen will generate a graph for each documented file showing the\n# direct and indirect include dependencies of the file with other documented\n# files.\n# The default value is: YES.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nINCLUDE_GRAPH          = YES\n\n# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are\n# set to YES then doxygen will generate a graph for each documented file showing\n# the direct and indirect include dependencies of the file with other documented\n# files.\n# The default value is: YES.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nINCLUDED_BY_GRAPH      = YES\n\n# If the CALL_GRAPH tag is set to YES then doxygen will generate a call\n# dependency graph for every global function or class method.\n#\n# Note that enabling this option will significantly increase the time of a run.\n# So in most cases it will be better to enable call graphs for selected\n# functions only using the \\callgraph command. Disabling a call graph can be\n# accomplished by means of the command \\hidecallgraph.\n# The default value is: NO.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nCALL_GRAPH             = NO\n\n# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller\n# dependency graph for every global function or class method.\n#\n# Note that enabling this option will significantly increase the time of a run.\n# So in most cases it will be better to enable caller graphs for selected\n# functions only using the \\callergraph command. Disabling a caller graph can be\n# accomplished by means of the command \\hidecallergraph.\n# The default value is: NO.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nCALLER_GRAPH           = NO\n\n# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical\n# hierarchy of all classes instead of a textual one.\n# The default value is: YES.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nGRAPHICAL_HIERARCHY    = YES\n\n# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the\n# dependencies a directory has on other directories in a graphical way. The\n# dependency relations are determined by the #include relations between the\n# files in the directories.\n# The default value is: YES.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nDIRECTORY_GRAPH        = YES\n\n# The DIR_GRAPH_MAX_DEPTH tag can be used to limit the maximum number of levels\n# of child directories generated in directory dependency graphs by dot.\n# Minimum value: 1, maximum value: 25, default value: 1.\n# This tag requires that the tag DIRECTORY_GRAPH is set to YES.\n\nDIR_GRAPH_MAX_DEPTH    = 1\n\n# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images\n# generated by dot. For an explanation of the image formats see the section\n# output formats in the documentation of the dot tool (Graphviz (see:\n# http://www.graphviz.org/)).\n# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order\n# to make the SVG files visible in IE 9+ (other browsers do not have this\n# requirement).\n# Possible values are: png, jpg, gif, svg, png:gd, png:gd:gd, png:cairo,\n# png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and\n# png:gdiplus:gdiplus.\n# The default value is: png.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nDOT_IMAGE_FORMAT       = png\n\n# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to\n# enable generation of interactive SVG images that allow zooming and panning.\n#\n# Note that this requires a modern browser other than Internet Explorer. Tested\n# and working are Firefox, Chrome, Safari, and Opera.\n# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make\n# the SVG files visible. Older versions of IE do not have SVG support.\n# The default value is: NO.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nINTERACTIVE_SVG        = NO\n\n# The DOT_PATH tag can be used to specify the path where the dot tool can be\n# found. If left blank, it is assumed the dot tool can be found in the path.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nDOT_PATH               =\n\n# The DOTFILE_DIRS tag can be used to specify one or more directories that\n# contain dot files that are included in the documentation (see the \\dotfile\n# command).\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nDOTFILE_DIRS           =\n\n# The MSCFILE_DIRS tag can be used to specify one or more directories that\n# contain msc files that are included in the documentation (see the \\mscfile\n# command).\n\nMSCFILE_DIRS           =\n\n# The DIAFILE_DIRS tag can be used to specify one or more directories that\n# contain dia files that are included in the documentation (see the \\diafile\n# command).\n\nDIAFILE_DIRS           =\n\n# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the\n# path where java can find the plantuml.jar file or to the filename of jar file\n# to be used. If left blank, it is assumed PlantUML is not used or called during\n# a preprocessing step. Doxygen will generate a warning when it encounters a\n# \\startuml command in this case and will not generate output for the diagram.\n\nPLANTUML_JAR_PATH      =\n\n# When using plantuml, the PLANTUML_CFG_FILE tag can be used to specify a\n# configuration file for plantuml.\n\nPLANTUML_CFG_FILE      =\n\n# When using plantuml, the specified paths are searched for files specified by\n# the !include statement in a plantuml block.\n\nPLANTUML_INCLUDE_PATH  =\n\n# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes\n# that will be shown in the graph. If the number of nodes in a graph becomes\n# larger than this value, doxygen will truncate the graph, which is visualized\n# by representing a node as a red box. Note that doxygen if the number of direct\n# children of the root node in a graph is already larger than\n# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that\n# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.\n# Minimum value: 0, maximum value: 10000, default value: 50.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nDOT_GRAPH_MAX_NODES    = 50\n\n# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs\n# generated by dot. A depth value of 3 means that only nodes reachable from the\n# root by following a path via at most 3 edges will be shown. Nodes that lay\n# further from the root node will be omitted. Note that setting this option to 1\n# or 2 may greatly reduce the computation time needed for large code bases. Also\n# note that the size of a graph can be further restricted by\n# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.\n# Minimum value: 0, maximum value: 1000, default value: 0.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nMAX_DOT_GRAPH_DEPTH    = 0\n\n# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output\n# files in one run (i.e. multiple -o and -T options on the command line). This\n# makes dot run faster, but since only newer versions of dot (>1.8.10) support\n# this, this feature is disabled by default.\n# The default value is: NO.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nDOT_MULTI_TARGETS      = NO\n\n# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page\n# explaining the meaning of the various boxes and arrows in the dot generated\n# graphs.\n# Note: This tag requires that UML_LOOK isn't set, i.e. the doxygen internal\n# graphical representation for inheritance and collaboration diagrams is used.\n# The default value is: YES.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nGENERATE_LEGEND        = YES\n\n# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate\n# files that are used to generate the various graphs.\n#\n# Note: This setting is not only used for dot files but also for msc temporary\n# files.\n# The default value is: YES.\n\nDOT_CLEANUP            = YES\n"
  },
  {
    "path": "LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2015 Torsten Robitzki\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\n"
  },
  {
    "path": "README.md",
    "content": "# Bluetoe [![Build Status](https://travis-ci.org/TorstenRobitzki/bluetoe.svg?branch=master)](https://travis-ci.org/TorstenRobitzki/bluetoe) [![Join the chat at https://gitter.im/TorstenRobitzki/bluetoe](https://badges.gitter.im/TorstenRobitzki/bluetoe.svg)](https://gitter.im/TorstenRobitzki/bluetoe?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Language grade: C/C++](https://img.shields.io/lgtm/grade/cpp/g/TorstenRobitzki/bluetoe.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/TorstenRobitzki/bluetoe/context:cpp)\n\n![Bluetoe Logo](https://github.com/TorstenRobitzki/bluetoe/blob/master/documentation/Logo_Bluetoe.svg?raw=true)\n\n## Putin's Invasion of Ukraine\n\nPlease consider donating to one of the funds that help victims of the war in Ukraine:\n- https://spendenkonto-nothilfe.de\n\n## Overview\n\nBluetoe implements a GATT server with a very low memory footprint and a convenient C++ interface. Bluetoe makes things easy but gives you the opportunity to fiddle with all the low-level GATT details if necessary. Bluetoe's primary target is very small microcontrollers. Here is a complete example of a small GATT server that allows a client to controll an IO pin, running on a nRF52832:\n\n    #include <bluetoe/server.hpp>\n    #include <bluetoe/device.hpp>\n    #include <nrf.h>\n\n    using namespace bluetoe;\n\n    // LED1 on a nRF52 eval board\n    static constexpr int io_pin = 17;\n\n    static std::uint8_t io_pin_write_handler( bool state )\n    {\n        // On an nRF52 eval board, the pin is connected to the LED's cathode. This inverts the logic.\n        NRF_GPIO->OUT = state\n            ? NRF_GPIO->OUT & ~( 1 << io_pin )\n            : NRF_GPIO->OUT | ( 1 << io_pin );\n\n        return error_codes::success;\n    }\n\n    using blinky_server = server<\n        service<\n            service_uuid< 0xC11169E1, 0x6252, 0x4450, 0x931C, 0x1B43A318783B >,\n            characteristic<\n                requires_encryption,\n                free_write_handler< bool, io_pin_write_handler >\n            >\n        >\n    >;\n\n    blinky_server gatt;\n\n    device< blinky_server > gatt_srv;\n\n    int main()\n    {\n        // Init GPIO pin\n        NRF_GPIO->PIN_CNF[ io_pin ] =\n            ( GPIO_PIN_CNF_DRIVE_S0H1 << GPIO_PIN_CNF_DRIVE_Pos ) |\n            ( GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos );\n\n        for ( ;; )\n            gatt_srv.run( gatt );\n    }\n\n## Documentation\n\nhttp://torstenrobitzki.github.io/bluetoe/\n\n## L2CAP\n\nBluetoe ships with its own fully-usable link layer based on the nRF52832. The link layer implementation is based and tested on an abstract device called a scheduled radio, and should be easy to port to similar hardware. As Bluetoe is a GATT server implementation, only parts of the link layer relevant to GATT have been implemented. Bluetoe can be easily adapted to any other existing L2CAP implementation (those based on HCI, for example).\n\n## Current State\n\nThe following table shows the list of supported GATT procedures, along with and their current and planned implementation status:\n\nFeature | Sub-Procedure | Status\n--------|---------------|-------\nServer Configuration|Exchange MTU|implemented\nPrimary Service Discovery|Discover All Primary Services|implemented\n<br/> |Discover Primary Service By Service UUID|implemented\nRelationship Discovery|Find Included Services|implemented\n<br/> |Declare Secondary Services|implemented\nCharacteristic Discovery|Discover All Characteristic of a Service|implemented\n<br/> |Discover Characteristic by UUID|implemented\nCharacteristic Descriptor Discovery|Discover All Characteristic Descriptors|implemented\nCharacteristic Value Read|Read Characteristic Value|implemented\n<br/> |Read Using Characteristic UUID|implemented\n<br/> |Read Long Characteristic Value|implemented\n<br/> |Read Multiple Characteristic Values|implemented\nCharacteristic Value Write| Write Without Response|implemented\n<br/> |Signed Write Without Response|not planned\n<br/> |Write Characteristic Value|implemented\n<br/> |Write Long Characteristic Values|implemented\n<br/> |Characteristic Value Reliable Writes|implemented\nCharacteristic Value Notification|Notifications|implemented\nCharacteristic Value Indication|Indications|implemented\nCharacteristic Descriptor Value Read|Read Characteristic Descriptors|implemented\n<br/> |Read Long Characteristic Descriptors|implemented\nCharacteristic Descriptor Value Write|Write Characteristic Descriptors|implemented\n<br/> |Write Long Characteristic Descriptors|implemented\nCryptography|Encryption|implemented\n<br/> |Authentication|planned\n\nThis is the current state of implemented Advertising Data:\n\nAdvertising Data|Format|Status\n----------------|------|------\nService UUID|Incomplete List of 16-bit Service UUIDs|implemented\n<br/> |Complete List of 16-bit Service UUIDs|implemented\n<br/> |Incomplete List of 32-bit Service UUIDs|not planned\n<br/> |Complete List of 32-bit Service UUIDs|not planned\n<br/> |Incomplete List of 128-bit Service UUIDs|implemented\n<br/> |Complete List of 128-bit Service UUIDs|implemented\nLocal Name|Shortened Local Name|implemented\n<br/> |Complete Local Name|implemented\nFlags|Flags|implemented\nManufacturer Specific Data|Manufacturer Specific Data|planned\nTX Power Level|TX Power Level|planned\nSecure Simple Pairing Out of Band||not planned\nSecurity Manager Out of Band||not planned\nSecurity Manager TK Value||not planned\nSlave Connection Interval Range||not planned\nService Solicitation||not planned\nService Data||not planned\nAppearance|Appearance|implemented\nLE Role|LE Role|planned\n\nThis is the current state of the Link Layer implementation:\n\nAspect | Feature | Status\n-------|---------|--------\nRoles|Slave Role|implemented\n<br/> |Master Role|not planned\nAdvertising|connectable undirected advertising|implemented\n<br/> |connectable directed advertising|implemented\n<br/> |non-connectable undirected advertising|implemented\n<br/> |scannable undirected advertising|implemented\nDevice Filtering||implemented\nConnections|Single Connection|implemented\n<br/> |Multiple Connection|not planned\nConnection|Slave Latency|planned\nFeature Support|LE Encryption|implemented\n<br/> |Connection Parameters Request Procedure|implemented\n<br/> |Extended Reject Indication|planned\n<br/> |Slave-initiated Features Exchange|planned\n<br/> |LE Ping|implemented\n<br/> |LE Data Packet Length Extension|planned\n<br/> |LL Privacy|not planned\n<br/> |Extended Scanner Filter Policies|not planned\n\n<br/> Pull requests are welcome.\n\n## Dependencies\n\n- Boost for Unit tests\n- CMake for build\n- A decent C++ compiler supporting C++11\n\n# Current Measurements\n\nAll measurements were done without any traffic and a slave latency of 0.\nAverage current was measured using various connection intervals.\n\n## nRF52840 blinky without encryption\n\n- Calibrated RC Sleep Clock (500ppm) (13608 Bytes binary size)\n  * 546µA average at 7.5ms\n  * 283µA average at 15ms\n  * 155µA average at 30ms\n\n- Crystal Oscilator Sleep Clock (20ppm) (13364 Bytes binary size)\n  * 526µA average at 7.5ms\n  * 207µA average at 15ms\n  * 143µA average at 30ms\n  * 22.4µA average at 660ms\n\n## nRF52840 blinky with encryption\n\n- Calibrated RC Sleep Clock (500ppm) (22848 Bytes binary size)\n  * 613µA average at 7.5ms\n  * 211µA average at 30ms\n  * 113µA average at 660ms\n\n- Crystal Oscilator Sleep Clock (20ppm) (22608 Bytes binary size)\n  * 589µA average at 7.5ms\n  * 197µA average at 30ms\n\n- Synthesized Sleep Clock (40ppm) (22596 Bytes binary size)\n  * 1.09mA average at 7.5ms\n  * 776µA average at 30ms\n\n- Old radio implementation (40ppm) (22212 Bytes binary size)\n  * 1.08mA average at 7.5ms\n  * 874µA average at 15ms\n  * 770µA average at 30ms\n  * 674µA average at 660ms\n\n## nRF52820 blinky with encryption\n\n- Calibrated RC Sleep Clock (500ppm / 1ms HFXO startup time) (21880 Bytes binary size)\n  * 347µA average at 15ms\n  * 217µA average at 30ms\n  * 94µA average at 660ms\n\n- Calibrated RC Sleep Clock (500ppm / 0.3ms HFXO startup time) (21880 Bytes binary size)\n  * 316µA average at 15ms\n  * 103µA average at 660ms\n\n\n\n"
  },
  {
    "path": "bluetoe/adv_service_list.hpp",
    "content": "#ifndef BLUETOE_ADV_SERVICE_LIST_HPP\n#define BLUETOE_ADV_SERVICE_LIST_HPP\n\n#include <bluetoe/codes.hpp>\n#include <bluetoe/bits.hpp>\n#include <bluetoe/meta_tools.hpp>\n#include <bluetoe/service_uuid.hpp>\n#include <bluetoe/meta_types.hpp>\n\n#include <algorithm>\n\nnamespace bluetoe {\n\n    namespace details {\n        struct list_of_16_bit_service_uuids_tag {};\n        struct list_of_128_bit_service_uuids_tag {};\n    }\n\n    /**\n     * @brief complete / incomplete list of 16 bit service UUIDs to be added to the advertising data\n     *\n     * If there is enough room to add all given UUIDs to the advertising data, a complete list AD type\n     * is added. If there is not enough room, the list will be incomplete. UUIDs from the beginning\n     * of the list are added as long as there is room. If there is no room for a single UUID, no\n     * advertising data is added.\n     */\n    template < typename ... UUID16 >\n    struct list_of_16_bit_service_uuids {\n        /** @cond HIDDEN_SYMBOLS */\n        struct meta_type\n            : details::list_of_16_bit_service_uuids_tag\n            , details::valid_server_option_meta_type\n        {};\n\n        static std::uint8_t* advertising_data( std::uint8_t* begin, std::uint8_t* end )\n        {\n            const std::size_t buffer_size = end - begin;\n\n            if ( buffer_size < 4 )\n                return begin;\n\n            const std::size_t max_uuids = std::min( (buffer_size - 2) / 2, sizeof ...(UUID16));\n\n            *begin = 1 + 2 * max_uuids;\n            ++begin;\n\n            *begin = max_uuids == sizeof ...(UUID16)\n                ? bits( details::gap_types::complete_service_uuids_16 )\n                : bits( details::gap_types::incomplete_service_uuids_16 );\n            ++begin;\n\n            for ( std::size_t uuid = 0; uuid != max_uuids; ++uuid )\n            {\n                begin = details::write_16bit( begin, values_[ uuid ] );\n            }\n\n            return begin;\n        }\n\n        static constexpr std::uint16_t values_[ sizeof ...(UUID16) ] = { UUID16::as_16bit()...};\n        /** @endcond */\n    };\n\n    /** @cond HIDDEN_SYMBOLS */\n    template < typename ... UUID16 >\n    constexpr std::uint16_t list_of_16_bit_service_uuids< UUID16... >::values_[ sizeof ...(UUID16) ];\n    /** @endcond */\n\n    /** @cond HIDDEN_SYMBOLS */\n    template <>\n    struct list_of_16_bit_service_uuids<> {\n        struct meta_type\n            : details::list_of_16_bit_service_uuids_tag\n            , details::valid_server_option_meta_type\n        {};\n\n        static std::uint8_t* advertising_data( std::uint8_t* begin, std::uint8_t* )\n        {\n            return begin;\n        }\n    };\n\n    template < typename ... UUID16 >\n    struct list_of_16_bit_service_uuids< std::tuple< UUID16... > > : list_of_16_bit_service_uuids< UUID16... > {};\n    /** @endcond */\n\n    struct no_list_of_service_uuids {\n        /** @cond HIDDEN_SYMBOLS */\n        struct meta_type\n            : details::list_of_16_bit_service_uuids_tag\n            , details::list_of_128_bit_service_uuids_tag\n            , details::valid_server_option_meta_type\n        {};\n\n        static constexpr std::uint8_t* advertising_data( std::uint8_t* begin, std::uint8_t* )\n        {\n            return begin;\n        }\n        /** @endcond */\n    };\n\n    namespace details {\n\n        struct uuid_128_writer\n        {\n            constexpr uuid_128_writer( std::uint8_t*& b, std::uint8_t* e )\n                : begin( b )\n                , end( e )\n            {\n            }\n\n            template< typename UUID >\n            void each()\n            {\n                if ( begin + sizeof( UUID::bytes ) <= end )\n                {\n                    std::copy( std::begin( UUID::bytes ), std::end( UUID::bytes ), begin );\n                    begin += sizeof( UUID::bytes );\n                }\n            }\n\n            std::uint8_t*&      begin;\n            std::uint8_t* const end;\n        };\n    }\n\n    template < typename ... UUID128 >\n    struct list_of_128_bit_service_uuids {\n        /** @cond HIDDEN_SYMBOLS */\n        struct meta_type :\n            details::list_of_128_bit_service_uuids_tag,\n            details::valid_server_option_meta_type {};\n\n        static std::uint8_t* advertising_data( std::uint8_t* begin, std::uint8_t* end )\n        {\n            static constexpr std::size_t uuid_size = 16;\n            const std::size_t buffer_size = end - begin;\n\n            if ( buffer_size < 2 + uuid_size )\n                return begin;\n\n            const std::size_t max_uuids = std::min( (buffer_size - 2) / uuid_size, sizeof ...(UUID128));\n\n            *begin = 1 + uuid_size * max_uuids;\n            ++begin;\n\n            *begin = max_uuids == sizeof ...(UUID128)\n                ? bits( details::gap_types::complete_service_uuids_128 )\n                : bits( details::gap_types::incomplete_service_uuids_128 );\n            ++begin;\n\n            details::for_< UUID128... >::each( details::uuid_128_writer( begin, end ) );\n\n            return begin;\n        }\n        /** @endcond */\n    };\n\n    /** @cond HIDDEN_SYMBOLS */\n    template < typename ... UUID16 >\n    struct list_of_128_bit_service_uuids< std::tuple< UUID16... > > : list_of_128_bit_service_uuids< UUID16... > {};\n\n    template <>\n    struct list_of_128_bit_service_uuids<> {\n        struct meta_type :\n            details::list_of_128_bit_service_uuids_tag,\n            details::valid_server_option_meta_type {};\n\n        static constexpr std::uint8_t* advertising_data( std::uint8_t* begin, std::uint8_t* ) {\n            return begin;\n        }\n    };\n    /** @endcond */\n\n    namespace details {\n        template < typename T >\n        struct extract_uuid {\n            using type = typename T::uuid;\n        };\n\n        template < typename Filter, typename ... Services >\n        struct create_list_of_service_uuids\n        {\n            typedef typename bluetoe::details::transform_list<\n                std::tuple< Services... >,\n                extract_uuid >::type uuids;\n\n            typedef typename find_all_by_meta_type< Filter, uuids >::type type;\n        };\n\n        template < typename ServiceList >\n        struct default_list_of_16_bit_service_uuids;\n\n        template < typename ... Services >\n        struct default_list_of_16_bit_service_uuids< std::tuple< Services... > > : list_of_16_bit_service_uuids<\n            typename create_list_of_service_uuids< bluetoe::details::service_uuid_16_meta_type, Services... >::type > {};\n\n        template < typename ServiceList >\n        struct default_list_of_128_bit_service_uuids;\n\n        template < typename ... Services >\n        struct default_list_of_128_bit_service_uuids< std::tuple< Services... > > : list_of_128_bit_service_uuids<\n            typename create_list_of_service_uuids< bluetoe::details::service_uuid_128_meta_type, Services... >::type > {};\n    }\n}\n\n#endif\n"
  },
  {
    "path": "bluetoe/appearance.hpp",
    "content": "#ifndef BLUETOE_APPEARANCE_HPP\n#define BLUETOE_APPEARANCE_HPP\n\n#include <bluetoe/meta_types.hpp>\n\nnamespace bluetoe {\n\n    namespace details {\n        struct device_appearance_meta_type {};\n        struct advertise_appearance_meta_type {};\n    }\n\n    /**\n     * @brief type to keep a bluetoe::appearance value\n     */\n    template < std::uint16_t A >\n    struct device_appearance\n    {\n        /** @cond HIDDEN_SYMBOLS */\n        struct meta_type :\n            details::device_appearance_meta_type,\n            details::valid_server_option_meta_type {};\n\n        static constexpr std::uint16_t                  value = A;\n        /** @endcond */\n    };\n\n    /**\n     * @brief enumeration of appearances (org.bluetooth.characteristic.gap.appearance)\n     *\n     * The class contains a lot of alias-declarations for known, assigned device appearances.\n     * Pass one of the types to the server definition, to define the appearance to the GATT client.\n     *\n     * This will define, the GAP Appearance Characteristic value of the GAP service for GATT server.\n     *\n     * @sa advertise_appearance\n     *\n     * @code\n    unsigned temperature_value = 0;\n\n    typedef bluetoe::server<\n        bluetoe::service<\n            bluetoe::appearance::thermometer,\n            bluetoe::advertise_appearance\n            ...\n        >\n    > small_temperature_service;\n     * @endcode\n     * @sa server\n     */\n    struct appearance\n    {\n        /// Unknown\n        using unknown                                 = device_appearance< 0x0000 >;\n        /// Generic Phone\n        using phone                                   = device_appearance< 0x0040 >;\n        /// Generic Computer\n        using computer                                = device_appearance< 0x0080 >;\n        /// Generic Watch\n        using watch                                   = device_appearance< 0x00c0 >;\n        /// Watch: Sports Watch\n        using sports_watch                            = device_appearance< 0x00c1 >;\n        /// Generic Clock\n        using clock                                   = device_appearance< 0x0100 >;\n        /// Generic Display\n        using display                                 = device_appearance< 0x0140 >;\n        /// Generic Remote Control\n        using remote_control                          = device_appearance< 0x0180 >;\n        /// Generic Eye-glasses\n        using eye_glasses                             = device_appearance< 0x01c0 >;\n        /// Generic Tag\n        using tag                                     = device_appearance< 0x0200 >;\n        /// Generic Keyring\n        using keyring                                 = device_appearance< 0x0240 >;\n        /// Generic Media Player\n        using media_player                            = device_appearance< 0x0280 >;\n        /// Generic Barcode Scanner\n        using barcode_scanner                         = device_appearance< 0x02c0 >;\n        /// Generic Thermometer\n        using thermometer                             = device_appearance< 0x0300 >;\n        /// Thermometer: Ear\n        using ear_thermometer                         = device_appearance< 0x0301 >;\n        /// Generic Heart rate Sensor\n        using heart_rate_sensor                       = device_appearance< 0x0340 >;\n        /// Heart Rate Sensor: Heart Rate Belt\n        using heart_rate_belt                         = device_appearance< 0x0341 >;\n        /// Generic Blood Pressure\n        using blood_pressure                          = device_appearance< 0x0380 >;\n        /// Blood Pressure: Arm\n        using blood_pressure_arm                      = device_appearance< 0x0381 >;\n        /// Blood Pressure: Wrist\n        using blood_pressure_wrist                    = device_appearance< 0x0382 >;\n        /// Human Interface Device (HID)\n        using human_interface_device                  = device_appearance< 0x03c0 >;\n        /// Keyboard (HID subtype)\n        using keyboard                                = device_appearance< 0x03c1 >;\n        /// Mouse (HID subtype)\n        using mouse                                   = device_appearance< 0x03c2 >;\n        /// Joystick (HID subtype)\n        using joystick                                = device_appearance< 0x03c3 >;\n        /// Gamepad (HID subtype)\n        using gamepad                                 = device_appearance< 0x03c4 >;\n        /// Digitizer Tablet (HID subtype)\n        using digitizer_tablet                        = device_appearance< 0x03c5 >;\n        /// Card Reader (HID subtype)\n        using card_reader                             = device_appearance< 0x03c6 >;\n        /// Digital Pen (HID subtype)\n        using digital_pen                             = device_appearance< 0x03c7 >;\n        /// Barcode Scanner (HID subtype)\n        using hid_barcode_scanner                     = device_appearance< 0x03c8 >;\n        /// Generic Glucose Meter\n        using glucose_meter                           = device_appearance< 0x0400 >;\n        /// Generic: Running Walking Sensor\n        using running_walking_sensor                  = device_appearance< 0x0440 >;\n        /// Running Walking Sensor: In-Shoe\n        using in_shoe_running_walking_sensor          = device_appearance< 0x0441 >;\n        /// Running Walking Sensor: On-Shoe\n        using on_shoe_running_walking_sensor          = device_appearance< 0x0442 >;\n        /// Running Walking Sensor: On-Hip\n        using on_hip_running_walking_sensor           = device_appearance< 0x0443 >;\n        /// Generic: Cycling\n        using cycling                                 = device_appearance< 0x0480 >;\n        /// Cycling: Cycling Computer\n        using cycling_computer                        = device_appearance< 0x0481 >;\n        /// Cycling: Speed Sensor\n        using cycling_speed_sensor                    = device_appearance< 0x0482 >;\n        /// Cycling: Cadence Sensor\n        using cycling_cadence_sensor                  = device_appearance< 0x0483 >;\n        /// Cycling: Power Sensor\n        using cycling_power_sensor                    = device_appearance< 0x0484 >;\n        /// Cycling: Speed and Cadence Sensor\n        using cycling_speed_and_cadence_sensor        = device_appearance< 0x0485 >;\n        /// Generic: Pulse Oximeter\n        using pulse_oximeter                          = device_appearance< 0x0c40 >;\n        /// Fingertip (Pulse Oximeter)\n        using fingertip_pulse_oximeter                = device_appearance< 0x0c41 >;\n        /// Wrist Worn (Pulse Oximeter)\n        using wrist_worn_pulse_oximeter               = device_appearance< 0x0c42 >;\n        /// Generic: Weight Scale\n        using weight_scale                            = device_appearance< 0x0c80 >;\n        /// Generic: Outdoor Sports Activity\n        using outdoor_sports_activity                 = device_appearance< 0x1440 >;\n        /// Location Display Device\n        using location_display_device                 = device_appearance< 0x1441 >;\n        /// Location and Navigation Display Device\n        using location_and_navigation_display_device  = device_appearance< 0x1442 >;\n        /// Location Pod\n        using location_pod                            = device_appearance< 0x1443 >;\n        /// Location and Navigation Pod\n        using location_and_navigation_pod             = device_appearance< 0x1444 >;\n    };\n\n    /**\n     * @brief add the appearance of the device to the advertising data\n     *\n     * If no advertising is configured, `unknown` appearance is advertised.\n     *\n     * @sa device_appearance\n     */\n    struct advertise_appearance\n    {\n        /** @cond HIDDEN_SYMBOLS */\n        struct meta_type :\n            details::advertise_appearance_meta_type,\n            details::valid_server_option_meta_type {};\n\n        template < typename Adv >\n        static std::uint8_t* advertising_data( std::uint8_t* begin, std::uint8_t* end )\n        {\n            static constexpr std::size_t adv_data_size = 4u;\n\n            if ( std::size_t(end - begin) >= adv_data_size )\n            {\n                *begin = static_cast< std::uint8_t >( adv_data_size - 1 );\n                ++begin;\n                *begin = bits( details::gap_types::appearance );\n                ++begin;\n                begin = details::write_16bit( begin, Adv::value );\n            }\n\n            return begin;\n        }\n        /** @endcond */\n    };\n\n    /** @cond HIDDEN_SYMBOLS */\n    // the default to use\n    struct no_advertise_appearance\n    {\n        struct meta_type :\n            details::advertise_appearance_meta_type,\n            details::valid_server_option_meta_type {};\n\n        template < typename >\n        static std::uint8_t* advertising_data( std::uint8_t* begin, std::uint8_t* )\n        {\n            return begin;\n        }\n    };\n    /** @endcond */\n}\n\n#endif // include guard\n"
  },
  {
    "path": "bluetoe/attribute_generator.hpp",
    "content": "#ifndef BLUETOE_ATTRIBUTE_GENERATOR_HPP\n#define BLUETOE_ATTRIBUTE_GENERATOR_HPP\n\n#include <tuple>\n#include <bluetoe/meta_tools.hpp>\n\nnamespace bluetoe {\nnamespace details {\n\n    /** @cond HIDDEN_SYMBOLS */\n\n    /**\n     *\n     */\n    template < typename, typename, std::size_t, typename, typename, typename ... Options >\n    struct generate_attribute;\n\n    /**\n     * generate a const static array of attributes out of a list of tuples, containing the parameter to generate an attribute\n     *\n     *  Attributes: A std::tuple, containing a tuple for every attribute to generate.\n     *\n     *  ClientCharacteristicIndex: The index of the characteristic to be generate in the containing service\n     *\n     *  Options: All options that where given to the characteristic\n     */\n    template < typename Attributes, typename CCCDIndices, std::size_t ClientCharacteristicIndex, typename Service, typename Server, typename ... Options >\n    struct generate_attribute_list;\n\n    template < typename CCCDIndices,std::size_t ClientCharacteristicIndex, typename Service, typename Server, typename ... Options >\n    struct generate_attribute_list< std::tuple<>, CCCDIndices, ClientCharacteristicIndex, Service, Server, std::tuple< Options... > >\n    {\n        static const attribute attribute_at( std::size_t )\n        {\n            assert( !\"should not happen\" );\n            return attribute();\n        }\n    };\n\n    template < typename ... Attributes, typename ... CCCDIndices, std::size_t ClientCharacteristicIndex, typename Service, typename Server, typename ... Options >\n    struct generate_attribute_list< std::tuple< Attributes... >, std::tuple< CCCDIndices... >, ClientCharacteristicIndex, Service, Server, std::tuple< Options... > >\n    {\n        static const attribute attribute_at( std::size_t index )\n        {\n            return attributes[ index ];\n        }\n\n        static const attribute attributes[ sizeof ...(Attributes) ];\n    };\n\n    template < typename ... Attributes, typename ... CCCDIndices, std::size_t ClientCharacteristicIndex, typename Service, typename Server, typename ... Options >\n    const attribute generate_attribute_list< std::tuple< Attributes... >, std::tuple< CCCDIndices... >, ClientCharacteristicIndex, Service, Server, std::tuple< Options... > >::attributes[ sizeof ...(Attributes) ] =\n    {\n        generate_attribute< Attributes, std::tuple< CCCDIndices... >, ClientCharacteristicIndex, Service, Server, Options... >::attr...\n    };\n\n    template < typename OptionsList, typename MetaTypeList, typename OptionsDefault = std::tuple<> >\n    struct count_attributes;\n\n    template < typename OptionsList, typename ... MetaTypes, typename OptionsDefault >\n    struct count_attributes< OptionsList, std::tuple< MetaTypes... >, OptionsDefault >\n    {\n        using attribute_generation_parameters = typename group_by_meta_types_without_empty_groups<\n            typename add_type< OptionsList, OptionsDefault >::type,\n            MetaTypes...\n        >::type;\n\n        enum { number_of_attributes = std::tuple_size< attribute_generation_parameters >::value };\n    };\n\n    template < typename OptionsList, typename MetaTypeList, typename CCCDIndices, typename OptionsDefault = std::tuple<> >\n    struct generate_attributes;\n\n    template < typename OptionsList, typename ... MetaTypes, typename CCCDIndices, typename OptionsDefault >\n    struct generate_attributes< OptionsList, std::tuple< MetaTypes... >, CCCDIndices, OptionsDefault >\n        : count_attributes< OptionsList, std::tuple< MetaTypes... >, OptionsDefault >\n    {\n        using attribute_generation_parameters = typename group_by_meta_types_without_empty_groups<\n            typename add_type< OptionsList, OptionsDefault >::type,\n            MetaTypes...\n        >::type;\n\n        attribute_generation_parameters get_attribute_generation_parameters() { return attribute_generation_parameters(); }\n\n        template < std::size_t ClientCharacteristicIndex, typename Service, typename Server >\n        static const attribute attribute_at( std::size_t index )\n        {\n            return generate_attribute_list<\n                attribute_generation_parameters,\n                CCCDIndices,\n                ClientCharacteristicIndex,\n                Service,\n                Server,\n                OptionsList\n            >::attribute_at( index );\n        }\n    };\n\n    /** @endcond */\n}\n}\n\n#endif // include guard\n"
  },
  {
    "path": "bluetoe/attribute_handle.hpp",
    "content": "#ifndef BLUETOE_ATTRIBUTE_HANDLE_HPP\n#define BLUETOE_ATTRIBUTE_HANDLE_HPP\n\n#include <bluetoe/meta_types.hpp>\n#include <bluetoe/meta_tools.hpp>\n\n#include <cstdint>\n#include <cstdlib>\n#include <cassert>\n#include <algorithm>\n\nnamespace bluetoe {\n\n    namespace details {\n        struct attribute_handle_meta_type {};\n        struct attribute_handles_meta_type {};\n    }\n\n    /**\n     * @brief define the first attribute handle used by a characteristic or service\n     *\n     * If this option is given to a service, the service attribute will be assigned\n     * to the given handle value. For a characteristic, the Characteristic Declaration\n     * attribute will be assigned to the given handle value.\n     *\n     * All following attrbutes are assigned handles with a larger value.\n     *\n     * @sa attribute_handles\n     * @sa service\n     * @sa characteristic\n     */\n    template < std::uint16_t AttributeHandleValue >\n    struct attribute_handle\n    {\n        /** @cond HIDDEN_SYMBOLS */\n        static constexpr std::uint16_t attribute_handle_value = AttributeHandleValue;\n\n        struct meta_type :\n            details::attribute_handle_meta_type,\n            details::valid_service_option_meta_type,\n            details::valid_characteristic_option_meta_type {};\n        /** @endcond */\n    };\n\n    /**\n     * @brief define the attributes handles for the characteristic declaration, characteristic\n     *        value and optional, for a Client Characteristic Configuration descriptor.\n     *\n     * If the characteristic has no Client Characteristic Configuration descriptor, the CCCD\n     * parameter has to be 0. Value has to be larger than Declaration and CCCD has to larger\n     * than Value (or 0).\n     *\n     * @sa attribute_handle\n     * @sa characteristic\n     */\n    template < std::uint16_t Declaration, std::uint16_t Value, std::uint16_t CCCD = 0x0000 >\n    struct attribute_handles\n    {\n        /** @cond HIDDEN_SYMBOLS */\n        static constexpr std::uint16_t declaration_handle = Declaration;\n        static constexpr std::uint16_t value_handle       = Value;\n        static constexpr std::uint16_t cccd_handle        = CCCD;\n\n        static_assert( value_handle > declaration_handle, \"value handle has to be larger than declaration handle\" );\n        static_assert( cccd_handle > declaration_handle || cccd_handle == 0, \"CCCD handle has to be larger than declaration handle\" );\n        static_assert( cccd_handle > value_handle || cccd_handle == 0, \"CCCD handle has to be larger than value handle\" );\n\n        struct meta_type :\n            details::attribute_handles_meta_type,\n            details::valid_characteristic_option_meta_type {};\n        /** @endcond */\n    };\n\n    template < typename ... Options >\n    class server;\n\n    template < typename ... Options >\n    class service;\n\n    template < typename ... Options >\n    class characteristic;\n\n    namespace details {\n\n        static constexpr std::uint16_t invalid_attribute_handle = 0;\n        static constexpr std::size_t   invalid_attribute_index  = ~0;\n\n        /*\n         * select one of attribute_handle< H > or attribute_handle< H, B, C >\n         */\n        template < std::uint16_t Default, class, class >\n        struct select_attribute_handles\n        {\n            static constexpr std::uint16_t declaration_handle = Default;\n            static constexpr std::uint16_t value_handle       = Default + 1;\n            static constexpr std::uint16_t cccd_handle        = Default + 2;\n        };\n\n        template < std::uint16_t Default, std::uint16_t AttributeHandleValue, typename T >\n        struct select_attribute_handles< Default, attribute_handle< AttributeHandleValue >, T >\n        {\n            static constexpr std::uint16_t declaration_handle = AttributeHandleValue;\n            static constexpr std::uint16_t value_handle       = AttributeHandleValue + 1;\n            static constexpr std::uint16_t cccd_handle        = AttributeHandleValue + 2;\n        };\n\n        template < std::uint16_t Default, typename T, std::uint16_t Declaration, std::uint16_t Value, std::uint16_t CCCD >\n        struct select_attribute_handles< Default, T, attribute_handles< Declaration, Value, CCCD > >\n        {\n            static constexpr std::uint16_t declaration_handle = Declaration;\n            static constexpr std::uint16_t value_handle       = Value;\n            static constexpr std::uint16_t cccd_handle        = CCCD == 0 ? Value + 1 : CCCD;\n        };\n\n        template < std::uint16_t Default, std::uint16_t AttributeHandleValue, std::uint16_t Declaration, std::uint16_t Value, std::uint16_t CCCD >\n        struct select_attribute_handles< Default, attribute_handle< AttributeHandleValue >, attribute_handles< Declaration, Value, CCCD > >\n        {\n            static_assert( Declaration == Value, \"either attribute_handle<> or attribute_handles<> can be used as characteristic<> option, not both.\" );\n        };\n\n        template < std::uint16_t StartHandle, std::uint16_t StartIndex, typename ... Options >\n        struct characteristic_index_mapping\n        {\n            using characteristic_t = ::bluetoe::characteristic< Options... >;\n\n            using attribute_handles_t = select_attribute_handles< StartHandle,\n                typename find_by_meta_type< attribute_handle_meta_type, Options... >::type,\n                typename find_by_meta_type< attribute_handles_meta_type, Options... >::type\n            >;\n\n            static_assert( attribute_handles_t::declaration_handle >= StartHandle, \"attribute_handle<> can only be used to create increasing attribute handles.\" );\n\n            static constexpr std::uint16_t end_handle   = characteristic_t::number_of_attributes == 2\n                ? attribute_handles_t::value_handle + 1\n                : attribute_handles_t::cccd_handle + ( characteristic_t::number_of_attributes - 2 );\n            static constexpr std::uint16_t end_index    = StartIndex + characteristic_t::number_of_attributes;\n\n            static constexpr std::size_t declaration_position = 0;\n            static constexpr std::size_t value_position       = 1;\n            static constexpr std::size_t cccd_position        = 2;\n\n            static std::uint16_t characteristic_attribute_handle_by_index( std::size_t index )\n            {\n                const std::size_t relative_index = index - StartIndex;\n\n                assert( relative_index < characteristic_t::number_of_attributes );\n\n                switch ( relative_index )\n                {\n                    case declaration_position:\n                        return attribute_handles_t::declaration_handle;\n                        break;\n\n                    case value_position:\n                        return attribute_handles_t::value_handle;\n                        break;\n\n                    case cccd_position:\n                        return attribute_handles_t::cccd_handle;\n                        break;\n                }\n\n                return relative_index - cccd_position + attribute_handles_t::cccd_handle;\n            }\n\n            static std::size_t characteristic_attribute_index_by_handle( std::uint16_t handle )\n            {\n                if ( handle <= attribute_handles_t::declaration_handle )\n                    return StartIndex + declaration_position;\n\n                if ( handle <= attribute_handles_t::value_handle )\n                    return StartIndex + value_position;\n\n                if ( handle <= attribute_handles_t::cccd_handle )\n                    return StartIndex + cccd_position;\n\n                return StartIndex + cccd_position + handle - attribute_handles_t::cccd_handle;\n            }\n        };\n\n        template < std::uint16_t StartHandle, std::uint16_t StartIndex, typename CharacteristicList >\n        struct interate_characteristic_index_mappings;\n\n        template < std::uint16_t StartHandle, std::uint16_t StartIndex >\n        struct interate_characteristic_index_mappings< StartHandle, StartIndex, std::tuple<> >\n        {\n            static std::uint16_t attribute_handle_by_index( std::size_t )\n            {\n                return invalid_attribute_handle;\n            }\n\n            static std::size_t attribute_index_by_handle( std::uint16_t )\n            {\n                return invalid_attribute_index;\n            }\n\n            static constexpr std::uint16_t last_characteristic_end_handle = StartHandle;\n        };\n\n        template < std::uint16_t StartHandle, std::uint16_t StartIndex, typename Characteristics, typename ... Options >\n        using next_characteristic_mapping = interate_characteristic_index_mappings<\n            characteristic_index_mapping< StartHandle, StartIndex, Options... >::end_handle,\n            characteristic_index_mapping< StartHandle, StartIndex, Options... >::end_index,\n            Characteristics\n        >;\n\n        template < std::uint16_t StartHandle, std::uint16_t StartIndex, typename ...Options, typename ... Chars >\n        struct interate_characteristic_index_mappings< StartHandle, StartIndex, std::tuple< ::bluetoe::characteristic< Options... >, Chars... > >\n            : characteristic_index_mapping< StartHandle, StartIndex, Options... >\n            , next_characteristic_mapping< StartHandle, StartIndex, std::tuple< Chars... >, Options... >\n        {\n            static constexpr std::uint16_t last_characteristic_end_handle =\n                next_characteristic_mapping< StartHandle, StartIndex, std::tuple< Chars... >, Options... >::last_characteristic_end_handle;\n\n            using next = characteristic_index_mapping< StartHandle, StartIndex, Options... >;\n\n            static std::uint16_t attribute_handle_by_index( std::size_t index )\n            {\n                if ( index < next::end_index )\n                    return next::characteristic_attribute_handle_by_index( index );\n\n                return next_characteristic_mapping< StartHandle, StartIndex, std::tuple< Chars... >, Options... >::attribute_handle_by_index( index );\n            }\n\n            static std::size_t attribute_index_by_handle( std::uint16_t handle )\n            {\n                if ( handle < next::end_handle )\n                    return next::characteristic_attribute_index_by_handle( handle );\n\n                return next_characteristic_mapping< StartHandle, StartIndex, std::tuple< Chars... >, Options... >::attribute_index_by_handle( handle );\n            }\n        };\n\n        template < std::uint16_t StartHandle, std::uint16_t StartIndex, typename ... Options >\n        struct service_start_handle\n        {\n            using start_handle_t = typename find_by_meta_type< attribute_handle_meta_type, Options..., attribute_handle< StartHandle > >::type;\n\n            static constexpr std::uint16_t value = start_handle_t::attribute_handle_value;\n        };\n\n        template < std::uint16_t StartHandle, std::uint16_t StartIndex, typename ... Options >\n        using next_char_mapping = interate_characteristic_index_mappings<\n                service_start_handle< StartHandle, StartIndex, Options... >::value + 1, StartIndex + 1,\n                typename find_all_by_meta_type< characteristic_meta_type, Options... >::type >;\n\n        /*\n         * Map index to handle within a single service\n         */\n        template < std::uint16_t StartHandle, std::uint16_t StartIndex, typename ... Options >\n        struct service_index_mapping\n            : next_char_mapping< StartHandle, StartIndex, Options... >\n        {\n            using service_t = ::bluetoe::service< Options... >;\n\n            static constexpr std::uint16_t service_handle = service_start_handle< StartHandle, StartIndex, Options... >::value;\n\n            static_assert( service_handle >= StartHandle, \"attribute_handle<> can only be used to create increasing attribute handles.\" );\n\n            static constexpr std::uint16_t end_handle   = next_char_mapping< StartHandle, StartIndex, Options... >::last_characteristic_end_handle;\n            static constexpr std::uint16_t end_index    = StartIndex + service_t::number_of_attributes;\n\n            static std::uint16_t characteristic_handle_by_index( std::size_t index )\n            {\n                if ( index == StartIndex )\n                    return service_handle;\n\n                return next_char_mapping< StartHandle, StartIndex, Options... >::attribute_handle_by_index( index );\n            }\n\n            static std::size_t characteristic_first_index_by_handle( std::uint16_t handle )\n            {\n                if ( handle <= service_handle )\n                    return StartIndex;\n\n                return next_char_mapping< StartHandle, StartIndex, Options... >::attribute_index_by_handle( handle );\n            }\n        };\n\n        /*\n         * Iterate over all services in a server\n         */\n        template < std::uint16_t StartHandle, std::uint16_t StartIndex, typename OptionTuple >\n        struct interate_service_index_mappings;\n\n        template < std::uint16_t StartHandle, std::uint16_t StartIndex >\n        struct interate_service_index_mappings< StartHandle, StartIndex, std::tuple<> >\n        {\n            static std::uint16_t service_handle_by_index( std::size_t )\n            {\n                return invalid_attribute_handle;\n            }\n\n            static std::size_t service_first_index_by_handle( std::uint16_t )\n            {\n                return invalid_attribute_index;\n            }\n        };\n\n        template < std::uint16_t StartHandle, std::uint16_t StartIndex, typename Services, typename ... Options >\n        using next_service_mapping = interate_service_index_mappings<\n            service_index_mapping< StartHandle, StartIndex, Options... >::end_handle,\n            service_index_mapping< StartHandle, StartIndex, Options... >::end_index,\n            Services\n        >;\n\n        template < std::uint16_t StartHandle, std::uint16_t StartIndex, typename ... Options, typename ... Services >\n        struct interate_service_index_mappings< StartHandle, StartIndex, std::tuple< ::bluetoe::service< Options... >, Services... > >\n            : service_index_mapping< StartHandle, StartIndex, Options... >\n            , next_service_mapping< StartHandle, StartIndex, std::tuple< Services... >, Options... >\n        {\n            static std::uint16_t service_handle_by_index( std::size_t index )\n            {\n                if ( index < service_index_mapping< StartHandle, StartIndex, Options... >::end_index )\n                    return service_index_mapping< StartHandle, StartIndex, Options... >::characteristic_handle_by_index( index );\n\n                return next_service_mapping< StartHandle, StartIndex, std::tuple< Services... >, Options... >::service_handle_by_index( index );\n            }\n\n            static std::size_t service_first_index_by_handle( std::uint16_t handle )\n            {\n                if ( handle < service_index_mapping< StartHandle, StartIndex, Options... >::end_handle )\n                    return service_index_mapping< StartHandle, StartIndex, Options... >::characteristic_first_index_by_handle( handle );\n\n                return next_service_mapping< StartHandle, StartIndex, std::tuple< Services... >, Options... >::service_first_index_by_handle( handle );\n            }\n        };\n\n        /*\n         * Interface, providing function to map from 0-based attribute index to ATT attribute handle and vice versa\n         *\n         * An attribute index is a 0-based into an array of all attributes contained in a server. Accessing the\n         * attribute by table is very fast. If neither attribute_handle<> or attribute_handles<> is used, the mapping\n         * is trivial and an index I is mapped to a handle I + 1.\n         */\n        template < typename Server >\n        struct handle_index_mapping;\n\n        template < typename ... Options >\n        struct handle_index_mapping< ::bluetoe::server< Options... > >\n            : private interate_service_index_mappings< 1u, 0u, typename ::bluetoe::server< Options... >::services >\n        {\n            static constexpr std::size_t   invalid_attribute_index  = ::bluetoe::details::invalid_attribute_index;\n            static constexpr std::uint16_t invalid_attribute_handle = ::bluetoe::details::invalid_attribute_handle;\n\n            using iterator = interate_service_index_mappings< 1u, 0u, typename ::bluetoe::server< Options... >::services >;\n\n            static std::uint16_t handle_by_index( std::size_t index )\n            {\n                return iterator::service_handle_by_index( index );\n            }\n\n            /**\n             * @brief attribute index for a given handle\n             *\n             * Returns the index to the attribute with the lowest handle that is\n             * equal or larger than the given handle.\n             */\n            static std::size_t first_index_by_handle( std::uint16_t handle )\n            {\n                return iterator::service_first_index_by_handle( handle );\n            }\n\n            static std::size_t index_by_handle( std::uint16_t handle )\n            {\n                std::size_t result = first_index_by_handle( handle );\n                if ( result != invalid_attribute_index && handle_by_index( result ) != handle )\n                    result = invalid_attribute_index;\n\n                return result;\n            }\n        };\n\n    }\n}\n\n#endif\n\n"
  },
  {
    "path": "bluetoe/bindings/CMakeLists.txt",
    "content": "add_subdirectory(nordic)"
  },
  {
    "path": "bluetoe/bindings/hci/include_libusb/bluetoe/device.hpp",
    "content": "#ifndef BLUETOE_BINDINGS_HCI_DEVICE_HPP\n#define BLUETOE_BINDINGS_HCI_DEVICE_HPP\n\n#include <bluetoe/link_layer.hpp>\n#include <bluetoe/libsub.hpp>\n\nnamespace bluetoe\n{\n    template < class Server, typename ... Options >\n    using device = bluetoe::hci::link_layer< Server, hci_details::libsub_transport, Options... >;\n}\n\n#endif\n\n"
  },
  {
    "path": "bluetoe/bindings/hci/include_libusb/bluetoe/libsub.hpp",
    "content": "#ifndef BLUETOE_BINDINGS_HCI_LIBUSB_HPP\n#define BLUETOE_BINDINGS_HCI_LIBUSB_HPP\n\nnamespace bluetoe {\n\n    namespace hci_details {\n        template < typename LinkLayer >\n        class libsub_transport {\n\n        };\n    }\n}\n\n#endif\n"
  },
  {
    "path": "bluetoe/bindings/nordic/CMakeLists.txt",
    "content": "add_library(bluetoe_bindings_nordic INTERFACE EXCLUDE_FROM_ALL)\nadd_library(bluetoe::bindings::nordic ALIAS bluetoe_bindings_nordic)\n\ntarget_include_directories(bluetoe_bindings_nordic INTERFACE include)\ntarget_link_libraries(bluetoe_bindings_nordic\n    INTERFACE\n        toolchain::${BINDING})\n\nadd_subdirectory(uECC)\nadd_subdirectory(nrf51)\nadd_subdirectory(nrf52)\n\n"
  },
  {
    "path": "bluetoe/bindings/nordic/include/bluetoe/nrf.hpp",
    "content": "#ifndef BLUETOE_BINDINGS_NRF_HPP\n#define BLUETOE_BINDINGS_NRF_HPP\n\n#include <bluetoe/meta_types.hpp>\n#include <bluetoe/default_pdu_layout.hpp>\n\n#include <nrf.h>\n\nnamespace bluetoe\n{\n    namespace nrf52_details {\n        void gpio_debug_hfxo_stopped();\n        void init_calibration_timer();\n        void deassign_hfxo();\n    }\n\n    /**\n     * @brief namespace with nRF51/52 specific configuration options\n     */\n    namespace nrf\n    {\n        /*\n         * Some aliases that can be used in the debugger\n         */\n        static NRF_RADIO_Type* const        nrf_radio            = NRF_RADIO;\n        static NRF_TIMER_Type* const        nrf_timer            = NRF_TIMER0;\n        static NRF_TIMER_Type* const        nrf_cb_timer         = NRF_TIMER1;\n        static NRF_CLOCK_Type* const        nrf_clock            = NRF_CLOCK;\n        static NRF_TEMP_Type* const         nrf_temp             = NRF_TEMP;\n        static NRF_RTC_Type* const          nrf_rtc              = NRF_RTC0;\n        static NRF_CCM_Type* const          nrf_ccm              = NRF_CCM;\n        static NRF_AAR_Type* const          nrf_aar              = NRF_AAR;\n        static NRF_PPI_Type* const          nrf_ppi              = NRF_PPI;\n        static NRF_RNG_Type* const          nrf_random           = NRF_RNG;\n        static NRF_ECB_Type* const          nrf_aes              = NRF_ECB;\n        static NRF_GPIOTE_Type* const       nrf_gpiote           = NRF_GPIOTE;\n        static NVIC_Type* const             nvic                 = NVIC;\n\n        static constexpr auto lfxo_clk_freq = 32768;\n\n        /*\n         * Interrupt priorities\n         */\n        static constexpr uint32_t nrf_interrupt_prio_ble = 0;\n        static constexpr uint32_t nrf_interrupt_prio_user_cb = 1 << ( __NVIC_PRIO_BITS - 1 );\n        static constexpr uint32_t nrf_interrupt_prio_calibrate_rtc = nrf_interrupt_prio_user_cb - 1;\n\n        namespace nrf_details {\n            struct radio_option_meta_type : ::bluetoe::details::binding_option_meta_type {};\n            struct sleep_clock_source_meta_type : radio_option_meta_type {};\n            struct hfxo_startup_time_meta_type : radio_option_meta_type {};\n            struct leave_run_on_interrupt_type : radio_option_meta_type {};\n\n            static void start_high_frequency_clock()\n            {\n                // This tasks starts the high frequency crystal oscillator (HFXO)\n                nrf_clock->TASKS_HFCLKSTART = 1;\n\n                // TODO: do not wait busy\n                // Issue: do not poll for readiness of the high frequency clock #63\n                while ( !nrf_clock->EVENTS_HFCLKSTARTED )\n                    ;\n\n                nrf_clock->EVENTS_HFCLKSTARTED = 0;\n            }\n\n            inline void start_lfclock_and_rtc()\n            {\n                nrf_clock->EVENTS_LFCLKSTARTED = 0;\n                nrf_clock->TASKS_LFCLKSTART = 1;\n\n                while ( nrf_clock->EVENTS_LFCLKSTARTED == 0 )\n                    ;\n\n                // https://infocenter.nordicsemi.com/topic/errata_nRF52840_Rev3/ERR/nRF52840/Rev3/latest/anomaly_840_20.html#anomaly_840_20\n                nrf_rtc->TASKS_STOP = 0;\n                nrf_rtc->TASKS_START = 1;\n\n                // Configure the RTC to generate these two events\n                // Overflow flag does not harm the power performance much and is used for\n                // debugging.\n                nrf_rtc->EVTEN =\n                    ( RTC_EVTEN_COMPARE0_Enabled << RTC_EVTEN_COMPARE0_Pos )\n                  | ( RTC_EVTEN_COMPARE1_Enabled << RTC_EVTEN_COMPARE1_Pos )\n                  | ( RTC_EVTEN_OVRFLW_Enabled << RTC_EVTEN_OVRFLW_Pos );\n            }\n        }\n\n        /**\n         * @brief configure the low frequency clock to be sourced out of the high frequency clock\n         *\n         * The resulting sleep clock accurary is then the accuarcy of your high frequency clock source.\n         *\n         * @sa bluetoe::link_layer::sleep_clock_accuracy_ppm\n         * @sa bluetoe::nrf::sleep_clock_crystal_oscillator\n         * @sa bluetoe::nrf::calibrated_rc_sleep_clock\n         */\n        struct synthesized_sleep_clock\n        {\n            /** @cond HIDDEN_SYMBOLS */\n            using meta_type = nrf_details::sleep_clock_source_meta_type;\n\n            static void start_clocks()\n            {\n                nrf_details::start_high_frequency_clock();\n\n                nrf_clock->LFCLKSRC = CLOCK_LFCLKSRCCOPY_SRC_Synth << CLOCK_LFCLKSRCCOPY_SRC_Pos;\n                nrf_details::start_lfclock_and_rtc();\n            }\n\n            static void stop_high_frequency_crystal_oscilator()\n            {\n            }\n            /** @endcond */\n        };\n\n        /**\n         * @brief configure the low frequency clock to be sourced from a crystal oscilator\n         *\n         * @sa bluetoe::link_layer::sleep_clock_accuracy_ppm\n         * @sa bluetoe::nrf::synthesized_sleep_clock\n         * @sa bluetoe::nrf::calibrated_rc_sleep_clock\n         */\n        struct sleep_clock_crystal_oscillator\n        {\n            /** @cond HIDDEN_SYMBOLS */\n            using meta_type = nrf_details::sleep_clock_source_meta_type;\n\n            static void start_clocks()\n            {\n                nrf_details::start_high_frequency_clock();\n\n                nrf_clock->LFCLKSRC = CLOCK_LFCLKSRCCOPY_SRC_Xtal << CLOCK_LFCLKSRCCOPY_SRC_Pos;\n                nrf_details::start_lfclock_and_rtc();\n            }\n\n            static void stop_high_frequency_crystal_oscilator()\n            {\n                nrf_clock->TASKS_HFCLKSTOP = 1;\n\n#               if defined BLUETOE_NRF52_RADIO_DEBUG\n                    bluetoe::nrf52_details::gpio_debug_hfxo_stopped();\n#               endif\n\n            }\n            /** @endcond */\n        };\n\n        /**\n         * @brief configure the low frequency clock to run from the RC oscilator.\n         *\n         * That low frequency RC oscilator will be calibrated by the high frequency\n         * crystal oscilator periodically.\n         *\n         * According to the datasheet, the resulting sleep clock accuarcy is then 500ppm.\n         * If no sleep clock configuration is given, this is the default.\n         *\n         * @sa bluetoe::link_layer::sleep_clock_accuracy_ppm\n         * @sa bluetoe::nrf::synthesized_sleep_clock\n         * @sa bluetoe::nrf::sleep_clock_crystal_oscillator\n         */\n        struct calibrated_rc_sleep_clock\n        {\n            /** @cond HIDDEN_SYMBOLS */\n            using meta_type = nrf_details::sleep_clock_source_meta_type;\n\n            static void start_clocks()\n            {\n                nrf_details::start_high_frequency_clock();\n\n                nrf_clock->LFCLKSRC = CLOCK_LFCLKSRCCOPY_SRC_RC << CLOCK_LFCLKSRCCOPY_SRC_Pos;\n                nrf_details::start_lfclock_and_rtc();\n                nrf52_details::init_calibration_timer();\n            }\n\n            static void stop_high_frequency_crystal_oscilator()\n            {\n                nrf52_details::deassign_hfxo();\n            }\n            /** @endcond */\n        };\n\n        /**\n         * @brief configure the high frequency crystal oscillator startup time\n         *\n         * Unless bluetoe::nrf::synthesized_sleep_clock is used as the sleep clock\n         * source, the nRF52 binding is switching on and off the high frequency clock\n         * oscillator to save power. It's important that this parameter is in configured\n         * to meet the real hardwares startup time to have the best power perfomance\n         * _and_ a stable connection.\n         *\n         * The given value in µs is roundet up to the next full period of the low frequency\n         * clock (30.52µs).\n         *\n         * If this configuration value is not given, 300µs (bluetoe::nrf::high_frequency_crystal_oscillator_startup_time_default)\n         * is used as the default.\n         *\n         * @sa bluetoe::nrf::sleep_clock_crystal_oscillator\n         * @sa bluetoe::nrf::calibrated_rc_sleep_clock\n         */\n        template < unsigned StartupTimeMicroSeconds >\n        struct high_frequency_crystal_oscillator_startup_time\n        {\n            /** @cond HIDDEN_SYMBOLS */\n            using meta_type = nrf_details::hfxo_startup_time_meta_type;\n\n            static constexpr unsigned value = StartupTimeMicroSeconds;\n            /** @endcond */\n        };\n\n        /**\n         * @brief default value for the high frequency crystal oscillator startup time\n         *\n         * @sa bluetoe::nrf::high_frequency_crystal_oscillator_startup_time\n         */\n        using high_frequency_crystal_oscillator_startup_time_default = high_frequency_crystal_oscillator_startup_time< 300 >;\n\n        /**\n         * @brief configures the radio::run() function to return on every interrupt\n         *\n         * Usually, run() will return on a call to radio::wake(). With this option, run()\n         * will only block for a single call to the WFI ARM assembler instruction. Once that\n         * instruction returns, the function will be left.\n         */\n        struct leave_run_on_interrupt {\n            /** @cond HIDDEN_SYMBOLS */\n            using meta_type = nrf_details::leave_run_on_interrupt_type;\n            /** @endcond */\n        };\n    }\n\n    namespace nrf_details\n    {\n        struct encrypted_pdu_layout : bluetoe::link_layer::details::layout_base< encrypted_pdu_layout >\n        {\n            /** @cond HIDDEN_SYMBOLS */\n            static constexpr std::size_t header_size = sizeof( std::uint16_t );\n\n            using bluetoe::link_layer::details::layout_base< encrypted_pdu_layout >::header;\n\n            static std::uint16_t header( const std::uint8_t* pdu )\n            {\n                return ::bluetoe::details::read_16bit( pdu );\n            }\n\n            static void header( std::uint8_t* pdu, std::uint16_t header_value )\n            {\n                ::bluetoe::details::write_16bit( pdu, header_value );\n            }\n\n            static std::pair< std::uint8_t*, std::uint8_t* > body( const link_layer::read_buffer& pdu )\n            {\n                assert( pdu.size >= header_size );\n\n                return { &pdu.buffer[ header_size + 1 ], &pdu.buffer[ pdu.size ] };\n            }\n\n            static std::pair< const std::uint8_t*, const std::uint8_t* > body( const link_layer::write_buffer& pdu )\n            {\n                assert( pdu.size >= header_size );\n\n                return { &pdu.buffer[ header_size + 1 ], &pdu.buffer[ pdu.size ] };\n            }\n\n            static constexpr std::size_t data_channel_pdu_memory_size( std::size_t payload_size )\n            {\n                return header_size + payload_size + 1;\n            }\n            /** @endcond */\n        };\n    }\n}\n\n#endif\n\n"
  },
  {
    "path": "bluetoe/bindings/nordic/nrf51/CMakeLists.txt",
    "content": "add_library(bluetoe_bindings_nrf51 STATIC EXCLUDE_FROM_ALL\n            nrf51.cpp)\nadd_library(bluetoe::bindings::nrf51 ALIAS bluetoe_bindings_nrf51)\n\ntarget_include_directories(bluetoe_bindings_nrf51 PUBLIC include)\n\ntarget_link_libraries(bluetoe_bindings_nrf51\n    PUBLIC\n        bluetoe::utility\n        bluetoe::sm\n        bluetoe::iface\n        bluetoe::link_layer\n        bluetoe::bindings::nordic\n    PRIVATE\n        bluetoe::bindings::nrf::uecc\n        toolchain::${BINDING}\n)\n\ntarget_compile_features(bluetoe_bindings_nrf51 PRIVATE cxx_std_11)\ntarget_compile_options(bluetoe_bindings_nrf51 PRIVATE -Wall -pedantic -Wextra -Wfatal-errors -Wno-parentheses)\n"
  },
  {
    "path": "bluetoe/bindings/nordic/nrf51/include/bluetoe/device.hpp",
    "content": "#ifndef BLUETOE_DEVICE_HPP\n#define BLUETOE_DEVICE_HPP\n\n#include <bluetoe/nrf51.hpp>\n\nnamespace bluetoe\n{\n    template < class Server, typename ... Options >\n    using device = link_layer::link_layer<\n        Server,\n        nrf51_details::template scheduled_radio_factory<\n            nrf51_details::scheduled_radio_base_with_encryption< Options... >\n        >::template scheduled_radio,\n        Options...\n    >;\n}\n\n#endif //BLUETOE_DEVICE_HPP\n"
  },
  {
    "path": "bluetoe/bindings/nordic/nrf51/include/bluetoe/nrf51.hpp",
    "content": "#ifndef BLUETOE_BINDINGS_NRF51_HPP\n#define BLUETOE_BINDINGS_NRF51_HPP\n\n#include <bluetoe/link_layer.hpp>\n#include <bluetoe/ll_data_pdu_buffer.hpp>\n#include <bluetoe/nrf.hpp>\n#include <cstdint>\n\nextern \"C\" void RADIO_IRQHandler(void);\nextern \"C\" void TIMER0_IRQHandler(void);\n\nnamespace bluetoe\n{\n    namespace nrf51_details\n    {\n        /* Counter used for CCM */\n        struct counter {\n            std::uint32_t   low;\n            std::uint8_t    high;\n\n            // set to zero\n            counter();\n\n            void increment();\n            void copy_to( std::uint8_t* target ) const;\n        };\n\n        // map compile time callbacks to runtime callbacks for faster development cycles.\n        class adv_callbacks\n        {\n        public:\n            virtual void adv_received( const link_layer::read_buffer& receive ) = 0;\n            virtual void adv_timeout() = 0;\n            virtual void timeout() = 0;\n            virtual void end_event() = 0;\n\n            virtual link_layer::write_buffer received_data( const link_layer::read_buffer& ) = 0;\n            virtual link_layer::write_buffer next_transmit() = 0;\n            virtual link_layer::read_buffer allocate_receive_buffer() = 0;\n            virtual void load_transmit_counter() = 0;\n\n            virtual bool is_scan_request_in_filter_callback( const link_layer::device_address& ) const = 0;\n        };\n\n        class scheduled_radio_base\n        {\n        public:\n            class lock_guard\n            {\n            public:\n                lock_guard();\n                ~lock_guard();\n\n                lock_guard( const lock_guard& ) = delete;\n                lock_guard& operator=( const lock_guard& ) = delete;\n            private:\n                const std::uint32_t context_;\n            };\n\n            scheduled_radio_base( adv_callbacks&, std::uint32_t encrypted_area );\n            explicit scheduled_radio_base( adv_callbacks& );\n\n            void schedule_advertisment(\n                unsigned                        channel,\n                const link_layer::write_buffer& advertising_data,\n                const link_layer::write_buffer& response_data,\n                link_layer::delta_time          when,\n                const link_layer::read_buffer&  receive );\n\n            void set_access_address_and_crc_init( std::uint32_t access_address, std::uint32_t crc_init );\n\n            void run();\n\n            void wake_up();\n\n            std::uint32_t static_random_address_seed() const;\n\n            // no native white list implementation atm\n            static constexpr std::size_t radio_maximum_white_list_entries = 0;\n\n            static constexpr bool hardware_supports_encryption = false;\n\n            void increment_receive_packet_counter()\n            {\n            }\n\n            void increment_transmit_packet_counter()\n            {\n            }\n\n            /**\n             * @brief experimental interface to be called from a connection event callback\n             *\n             * To be called, once the CPU will be stopped due to flash memory eraseing.\n             */\n            void nrf_flash_memory_access_begin();\n            void nrf_flash_memory_access_end();\n\n        protected:\n\n            bluetoe::link_layer::delta_time start_connection_event_impl(\n                unsigned                        channel,\n                bluetoe::link_layer::delta_time start_receive,\n                bluetoe::link_layer::delta_time end_receive,\n                const link_layer::read_buffer&  receive_buffer );\n\n            void configure_encryption( bool receive, bool transmit );\n\n        private:\n            friend void ::RADIO_IRQHandler(void);\n            friend void ::TIMER0_IRQHandler(void);\n\n            bool is_valid_scan_request() const;\n            void stop_radio();\n\n            void adv_radio_interrupt();\n            void adv_timer_interrupt();\n            void evt_radio_interrupt();\n            void evt_timer_interrupt();\n            void radio_interrupt();\n            void timer_interrupt();\n\n            unsigned frequency_from_channel( unsigned channel ) const;\n\n            adv_callbacks& callbacks_;\n            volatile bool timeout_;\n            volatile bool received_;\n            volatile bool evt_timeout_;\n            volatile bool end_evt_;\n            volatile int  wake_up_;\n\n            static constexpr unsigned connection_event_type_base = 100;\n\n            enum class state {\n                idle,\n                // timeout while receiving, stopping the radio, waiting for the radio to become disabled\n                adv_transmitting,\n                adv_receiving,\n                adv_transmitting_response,\n                // connection event\n                evt_wait_connect    = connection_event_type_base,\n                evt_transmiting_closing,\n            };\n\n            volatile state                  state_;\n\n            bluetoe::link_layer::delta_time anchor_offset_;\n\n            link_layer::read_buffer         receive_buffer_;\n            link_layer::write_buffer        response_data_;\n            std::uint8_t                    empty_receive_[ 3 ];\n            bool                            receive_encrypted_;\n            bool                            transmit_encrypted_;\n            std::uint32_t                   encrypted_area_;\n        };\n\n        class scheduled_radio_base_with_encryption_base : public scheduled_radio_base\n        {\n        protected:\n            scheduled_radio_base_with_encryption_base( adv_callbacks& cbs, std::uint32_t scratch_area, std::uint32_t encrypted_area );\n\n            void load_transmit_packet_counter();\n\n            bluetoe::link_layer::delta_time start_connection_event(\n                unsigned                        channel,\n                bluetoe::link_layer::delta_time start_receive,\n                bluetoe::link_layer::delta_time end_receive,\n                const link_layer::read_buffer&  receive_buffer )\n            {\n                load_receive_packet_counter();\n                return start_connection_event_impl( channel, start_receive, end_receive, receive_buffer );\n            }\n\n        public:\n            static constexpr bool hardware_supports_lesc_pairing    = true;\n            static constexpr bool hardware_supports_legacy_pairing  = true;\n            static constexpr bool hardware_supports_encryption      = hardware_supports_lesc_pairing || hardware_supports_legacy_pairing;\n\n            /**\n             * security tool box required by legacy pairing\n             */\n            bluetoe::details::uint128_t create_srand();\n\n            bluetoe::details::longterm_key_t create_long_term_key();\n\n            bluetoe::details::uint128_t c1(\n                const bluetoe::details::uint128_t& temp_key,\n                const bluetoe::details::uint128_t& rand,\n                const bluetoe::details::uint128_t& p1,\n                const bluetoe::details::uint128_t& p2 ) const;\n\n            bluetoe::details::uint128_t s1(\n                const bluetoe::details::uint128_t& temp_key,\n                const bluetoe::details::uint128_t& srand,\n                const bluetoe::details::uint128_t& mrand );\n\n            /**\n             * security tool box required by LESC pairing\n             */\n            bool is_valid_public_key( const std::uint8_t* public_key ) const;\n\n            std::pair< bluetoe::details::ecdh_public_key_t, bluetoe::details::ecdh_private_key_t > generate_keys();\n\n            bluetoe::details::uint128_t select_random_nonce();\n\n            bluetoe::details::ecdh_shared_secret_t p256( const std::uint8_t* private_key, const std::uint8_t* public_key );\n\n            bluetoe::details::uint128_t f4( const std::uint8_t* u, const std::uint8_t* v, const std::array< std::uint8_t, 16 >& k, std::uint8_t z );\n\n            std::pair< bluetoe::details::uint128_t, bluetoe::details::uint128_t > f5(\n                const bluetoe::details::ecdh_shared_secret_t dh_key,\n                const bluetoe::details::uint128_t& nonce_central,\n                const bluetoe::details::uint128_t& nonce_periperal,\n                const bluetoe::link_layer::device_address& addr_controller,\n                const bluetoe::link_layer::device_address& addr_peripheral );\n\n            bluetoe::details::uint128_t f6(\n                const bluetoe::details::uint128_t& key,\n                const bluetoe::details::uint128_t& n1,\n                const bluetoe::details::uint128_t& n2,\n                const bluetoe::details::uint128_t& r,\n                const bluetoe::details::io_capabilities_t& io_caps,\n                const bluetoe::link_layer::device_address& addr_controller,\n                const bluetoe::link_layer::device_address& addr_peripheral );\n\n            std::uint32_t g2(\n                const std::uint8_t*                 u,\n                const std::uint8_t*                 v,\n                const bluetoe::details::uint128_t&  x,\n                const bluetoe::details::uint128_t&  y );\n\n            /**\n             * Functions required by IO capabilties\n             */\n            bluetoe::details::uint128_t create_passkey();\n\n            /**\n             * Functions required by the link layer\n             */\n            std::pair< std::uint64_t, std::uint32_t > setup_encryption( bluetoe::details::uint128_t key, std::uint64_t skdm, std::uint32_t ivm );\n\n            void start_receive_encrypted();\n            void start_transmit_encrypted();\n            void stop_receive_encrypted();\n            void stop_transmit_encrypted();\n\n            void increment_receive_packet_counter()\n            {\n                rx_counter_.increment();\n            }\n\n            void increment_transmit_packet_counter()\n            {\n                tx_counter_.increment();\n            }\n\n            /**\n             * @brief sets an IRK filter for incomming scan requests and connection requests\n             *\n             * Has to be called when the radio is not in a connection or after disconnected.\n             * Experimental!\n             */\n            void set_identity_resolving_key( const details::identity_resolving_key_t& irk );\n\n        private:\n            void load_receive_packet_counter();\n\n            counter     tx_counter_;\n            counter     rx_counter_;\n        };\n\n        /*\n         * There are some data structures where the size depends on the configuration of the link layer (namely the\n         * maximum MTU size).\n         */\n        template < typename ... Options >\n        class scheduled_radio_base_with_encryption : public scheduled_radio_base_with_encryption_base\n        {\n        protected:\n            scheduled_radio_base_with_encryption( adv_callbacks& cbs )\n                : scheduled_radio_base_with_encryption_base( cbs,\n                    reinterpret_cast< std::uintptr_t >( &scratch_area_.data[ 0 ] ),\n                    reinterpret_cast< std::uintptr_t >( &encrypted_message_.data[ 0 ] ) )\n            {\n            }\n\n        private:\n            // the value MAXPACKETSIZE from the documentation seems to be the maximum value, the size field can store,\n            // and is independent from the MTU size (https://devzone.nordicsemi.com/f/nordic-q-a/13123/what-is-actual-size-required-for-scratch-area-for-ccm-on-nrf52/50031#50031)\n            static constexpr std::size_t scratch_size   = 267;\n\n            struct alignas( 4 ) scratch_area_t {\n                std::uint8_t data[ scratch_size ];\n            } scratch_area_;\n\n            // TODO should be calculated with more accuracy base on the configuration of:\n            // - l2cap MAX MTU\n            // - implementation of Data Length Update procedure\n            struct alignas( 4 ) encrypted_message_t {\n                std::uint8_t data[ 260 ];\n            } encrypted_message_;\n        };\n\n        class scheduled_radio_without_encryption_base : public scheduled_radio_base\n        {\n        protected:\n            bluetoe::link_layer::delta_time start_connection_event(\n                unsigned                        channel,\n                bluetoe::link_layer::delta_time start_receive,\n                bluetoe::link_layer::delta_time end_receive,\n                const link_layer::read_buffer&  receive_buffer )\n            {\n                return start_connection_event_impl( channel, start_receive, end_receive, receive_buffer );\n            }\n\n            scheduled_radio_without_encryption_base( adv_callbacks& cbs ) : scheduled_radio_base( cbs, 0 )\n            {\n            }\n\n            void load_transmit_packet_counter()\n            {\n            }\n        };\n\n        template < std::size_t TransmitSize, std::size_t ReceiveSize, typename CallBack, typename Base >\n        class scheduled_radio :\n            public bluetoe::link_layer::ll_data_pdu_buffer< TransmitSize, ReceiveSize, scheduled_radio< TransmitSize, ReceiveSize, CallBack, Base > >,\n            private adv_callbacks,\n            public Base\n        {\n        public:\n            scheduled_radio() : Base( static_cast< adv_callbacks& >( *this ) )\n            {\n            }\n\n            bluetoe::link_layer::delta_time schedule_connection_event(\n                unsigned                                    channel,\n                bluetoe::link_layer::delta_time             start_receive,\n                bluetoe::link_layer::delta_time             end_receive,\n                bluetoe::link_layer::delta_time             /* connection_interval */ )\n            {\n                link_layer::read_buffer read;\n                {\n                    class Base::lock_guard lock;\n                    read = buffer::allocate_receive_buffer();\n                }\n\n                return this->start_connection_event( channel, start_receive, end_receive, read );\n            }\n        private:\n            using buffer = bluetoe::link_layer::ll_data_pdu_buffer< TransmitSize, ReceiveSize, scheduled_radio< TransmitSize, ReceiveSize, CallBack, Base > >;\n\n            void adv_received( const link_layer::read_buffer& receive ) override\n            {\n                static_cast< CallBack* >( this )->adv_received( receive );\n            }\n\n            void adv_timeout() override\n            {\n                static_cast< CallBack* >( this )->adv_timeout();\n            }\n\n            void timeout() override\n            {\n                static_cast< CallBack* >( this )->timeout();\n            }\n\n            void end_event() override\n            {\n                static_cast< CallBack* >( this )->end_event();\n            }\n\n            link_layer::write_buffer received_data( const link_layer::read_buffer& b ) override\n            {\n                // this function is called within an ISR context, so no need to disable interrupts\n                return this->received( b );\n            }\n\n            link_layer::write_buffer next_transmit() override\n            {\n                // this function is called within an ISR context, so no need to disable interrupts\n                return buffer::next_transmit();\n            }\n\n            link_layer::read_buffer allocate_receive_buffer() override\n            {\n                return buffer::allocate_receive_buffer();\n            }\n\n            void load_transmit_counter() override\n            {\n                this->load_transmit_packet_counter();\n            }\n\n            bool is_scan_request_in_filter_callback( const link_layer::device_address& addr ) const override\n            {\n                return static_cast< const CallBack* >( this )->is_scan_request_in_filter( addr );\n            }\n        };\n\n        template < typename Base >\n        struct scheduled_radio_factory\n        {\n            template < std::size_t TransmitSize, std::size_t ReceiveSize, typename CallBack >\n            using scheduled_radio = nrf51_details::scheduled_radio< TransmitSize, ReceiveSize, CallBack, Base >;\n        };\n    } // namespace nrf51_details\n\n    /*\n     * nrf51 without encryption\n     */\n    template < class Server, typename ... Options >\n    using nrf51_without_encryption = link_layer::link_layer<\n        Server,\n        nrf51_details::template scheduled_radio_factory<\n            nrf51_details::scheduled_radio_without_encryption_base\n        >::scheduled_radio,\n        Options... >;\n\n    /*\n     * nrf51 with encryption\n     */\n    template < class Server, typename ... Options >\n    using nrf51 = link_layer::link_layer<\n        Server,\n        nrf51_details::template scheduled_radio_factory<\n            nrf51_details::scheduled_radio_base_with_encryption< Options... >\n        >::template scheduled_radio,\n        Options... >;\n\n    namespace link_layer {\n\n        /** @cond HIDDEN_SYMBOLS */\n        /*\n         * specialize pdu_layout_by_radio<> for the radio that supports encryption to change the PDU layout\n         * to have that extra byte between header and body\n         */\n        template < std::size_t TransmitSize, std::size_t ReceiveSize, typename CallBack, typename ... Options >\n        struct pdu_layout_by_radio<\n            nrf51_details::scheduled_radio< TransmitSize, ReceiveSize, CallBack, nrf51_details::scheduled_radio_base_with_encryption< Options... > > >\n        {\n            /**\n             * When using encryption, the Radio and the AES CCM peripheral expect an \"RFU\" byte between LL header and\n             * payload.\n             */\n            using pdu_layout = bluetoe::nrf_details::encrypted_pdu_layout;\n        };\n        /** @endcond */\n   }\n\n} // namespace bluetoe\n\n#endif // include guard\n"
  },
  {
    "path": "bluetoe/bindings/nordic/nrf51/nrf51.cpp",
    "content": "#include <bluetoe/nrf51.hpp>\n\n#include <nrf.h>\n\n#include <cassert>\n#include <cstdint>\n#include <algorithm>\n#include <cstring>\n\n#include \"uECC.h\"\n\n/*\n * Compile this with BLUETOE_NRF51_RADIO_DEBUG defined to enable debugging\n */\n\nnamespace bluetoe {\nnamespace nrf51_details {\n\n    static NRF_RADIO_Type* const        nrf_radio            = NRF_RADIO;\n    static NRF_TIMER_Type* const        nrf_timer            = NRF_TIMER0;\n    static NRF_CCM_Type* const          nrf_ccm              = NRF_CCM;\n    static NRF_AAR_Type* const          nrf_aar              = NRF_AAR;\n    static NVIC_Type* const             nvic                 = NVIC;\n    static NRF_PPI_Type* const          nrf_ppi              = NRF_PPI;\n    static scheduled_radio_base*        instance             = nullptr;\n\n    // after T_IFS (150µs +- 2) at maximum, a connection request will be received (34 Bytes + 1 Byte preable, 4 Bytes Access Address and 3 Bytes CRC)\n    // plus some additional 20µs\n    static constexpr std::uint32_t      adv_reponse_timeout_us   = 152 + 42 * 8 + 20;\n    static constexpr std::uint8_t       maximum_advertising_pdu_size = 0x3f;\n\n    // Time reserved to setup a connection event in µs\n    // time measured to setup a connection event, using GCC 8.3.1 with -O0 is 12µs\n    static constexpr std::uint32_t      setup_connection_event_limit_us = 50;\n\n    static constexpr std::size_t        radio_address_ccm_crypt         = 25;\n    static constexpr std::size_t        radio_end_capture2_ppi_channel  = 27;\n    static constexpr std::size_t        compare0_txen_ppi_channel       = 20;\n    static constexpr std::size_t        compare0_rxen_ppi_channel       = 21;\n    static constexpr std::size_t        compare1_disable_ppi_channel    = 22;\n    static constexpr std::size_t        radio_bcmatch_aar_start_channel = 23;\n\n    static constexpr std::uint8_t       more_data_flag = 0x10;\n    static constexpr std::size_t        encryption_mic_size = 4;\n\n    static constexpr unsigned           us_from_packet_start_to_address_end = ( 1 + 4 ) * 8;\n    static constexpr unsigned           us_radio_rx_startup_time            = 138;\n    static constexpr unsigned           us_radio_tx_startup_time            = 140;\n    static constexpr unsigned           connect_request_size                = 36;\n\n    // position of the connecting address (AdvA)\n    static constexpr unsigned           connect_addr_offset                 = 2 + 6;\n\n#   if defined BLUETOE_NRF51_RADIO_DEBUG\n        static constexpr int debug_pin_end_crypt     = 11;\n        static constexpr int debug_pin_ready_disable = 13;\n        static constexpr int debug_pin_address_end   = 15;\n        static constexpr int debug_pin_keystream     = 17;\n        static constexpr int debug_pin_debug         = 6;\n\n        void init_debug()\n        {\n            for ( auto pin : { debug_pin_end_crypt, debug_pin_ready_disable,\n                                debug_pin_address_end, debug_pin_keystream, debug_pin_debug } )\n            {\n                NRF_GPIO->PIN_CNF[ pin ] =\n                    ( GPIO_PIN_CNF_DRIVE_S0H1 << GPIO_PIN_CNF_DRIVE_Pos ) |\n                    ( GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos );\n            }\n\n            NRF_GPIOTE->CONFIG[ 0 ] =\n                ( GPIOTE_CONFIG_MODE_Task << GPIOTE_CONFIG_MODE_Pos ) |\n                ( debug_pin_address_end << GPIOTE_CONFIG_PSEL_Pos ) |\n                ( GPIOTE_CONFIG_POLARITY_Toggle << GPIOTE_CONFIG_POLARITY_Pos ) |\n                ( GPIOTE_CONFIG_OUTINIT_Low << GPIOTE_CONFIG_OUTINIT_Pos );\n\n            NRF_GPIOTE->CONFIG[ 1 ] =\n                ( GPIOTE_CONFIG_MODE_Task << GPIOTE_CONFIG_MODE_Pos ) |\n                ( debug_pin_keystream << GPIOTE_CONFIG_PSEL_Pos ) |\n                ( GPIOTE_CONFIG_POLARITY_Toggle << GPIOTE_CONFIG_POLARITY_Pos ) |\n                ( GPIOTE_CONFIG_OUTINIT_Low << GPIOTE_CONFIG_OUTINIT_Pos );\n\n            NRF_GPIOTE->CONFIG[ 2 ] =\n                ( GPIOTE_CONFIG_MODE_Task << GPIOTE_CONFIG_MODE_Pos ) |\n                ( debug_pin_ready_disable << GPIOTE_CONFIG_PSEL_Pos ) |\n                ( GPIOTE_CONFIG_POLARITY_Toggle << GPIOTE_CONFIG_POLARITY_Pos ) |\n                ( GPIOTE_CONFIG_OUTINIT_Low << GPIOTE_CONFIG_OUTINIT_Pos );\n\n            NRF_GPIOTE->CONFIG[ 3 ] =\n                ( GPIOTE_CONFIG_MODE_Task << GPIOTE_CONFIG_MODE_Pos ) |\n                ( debug_pin_end_crypt << GPIOTE_CONFIG_PSEL_Pos ) |\n                ( GPIOTE_CONFIG_POLARITY_Toggle << GPIOTE_CONFIG_POLARITY_Pos ) |\n                ( GPIOTE_CONFIG_OUTINIT_Low << GPIOTE_CONFIG_OUTINIT_Pos );\n\n\n            NRF_PPI->CH[ 0 ].EEP = reinterpret_cast< std::uint32_t >( &NRF_RADIO->EVENTS_ADDRESS );\n            NRF_PPI->CH[ 0 ].TEP = reinterpret_cast< std::uint32_t >( &NRF_GPIOTE->TASKS_OUT[ 0 ] );\n\n            NRF_PPI->CH[ 1 ].EEP = reinterpret_cast< std::uint32_t >( &NRF_RADIO->EVENTS_END );\n            NRF_PPI->CH[ 1 ].TEP = reinterpret_cast< std::uint32_t >( &NRF_GPIOTE->TASKS_OUT[ 0 ] );\n\n            NRF_PPI->CH[ 2 ].EEP = reinterpret_cast< std::uint32_t >( &NRF_CCM->EVENTS_ENDCRYPT );\n            NRF_PPI->CH[ 2 ].TEP = reinterpret_cast< std::uint32_t >( &NRF_GPIOTE->TASKS_OUT[ 3 ] );\n\n            NRF_PPI->CH[ 3 ].EEP = reinterpret_cast< std::uint32_t >( &NRF_CCM->EVENTS_ENDKSGEN );\n            NRF_PPI->CH[ 3 ].TEP = reinterpret_cast< std::uint32_t >( &NRF_GPIOTE->TASKS_CLR[ 1 ] );\n\n            NRF_PPI->CH[ 4 ].EEP = reinterpret_cast< std::uint32_t >( &NRF_RADIO->EVENTS_READY );\n            NRF_PPI->CH[ 4 ].TEP = reinterpret_cast< std::uint32_t >( &NRF_GPIOTE->TASKS_OUT[ 2 ] );\n\n            NRF_PPI->CH[ 5 ].EEP = reinterpret_cast< std::uint32_t >( &NRF_RADIO->EVENTS_DISABLED );\n            NRF_PPI->CH[ 5 ].TEP = reinterpret_cast< std::uint32_t >( &NRF_GPIOTE->TASKS_OUT[ 2 ] );\n\n            NRF_PPI->CHENSET = 0x3f;\n        }\n\n#   else\n        void init_debug() {}\n#   endif\n\n    counter::counter()\n        : low( 0 )\n        , high( 0 )\n    {\n    }\n\n    void counter::increment()\n    {\n        ++low;\n\n        if ( low == 0 )\n            ++high;\n    }\n\n    void counter::copy_to( std::uint8_t* target ) const\n    {\n        target  = details::write_32bit( target, low );\n        *target = high;\n    }\n\n    /*\n     * Frequency correction if NRF_FICR_Type has an OVERRIDEEN field\n     */\n    template < typename F, typename R >\n    static auto override_correction(F* ficr, R* radio) -> decltype(F::OVERRIDEEN)\n    {\n#       ifndef FICR_OVERRIDEEN_BLE_1MBIT_Msk\n#           define FICR_OVERRIDEEN_BLE_1MBIT_Msk 1\n#       endif\n#       ifndef FICR_OVERRIDEEN_BLE_1MBIT_Override\n#           define FICR_OVERRIDEEN_BLE_1MBIT_Override 1\n#       endif\n#       ifndef FICR_OVERRIDEEN_BLE_1MBIT_Pos\n#           define FICR_OVERRIDEEN_BLE_1MBIT_Pos 1\n#       endif\n\n        if ( ( ficr->OVERRIDEEN & FICR_OVERRIDEEN_BLE_1MBIT_Msk ) == (FICR_OVERRIDEEN_BLE_1MBIT_Override << FICR_OVERRIDEEN_BLE_1MBIT_Pos) )\n        {\n            radio->OVERRIDE0 = ficr->BLE_1MBIT[0];\n            radio->OVERRIDE1 = ficr->BLE_1MBIT[1];\n            radio->OVERRIDE2 = ficr->BLE_1MBIT[2];\n            radio->OVERRIDE3 = ficr->BLE_1MBIT[3];\n            radio->OVERRIDE4 = ficr->BLE_1MBIT[4] | 0x80000000;\n        }\n\n        return ficr->OVERRIDEEN;\n    }\n\n    template < typename F >\n    static void override_correction(...)\n    {\n    }\n\n    static void init_radio( bool encryption_possible )\n    {\n        override_correction< NRF_FICR_Type >( NRF_FICR, NRF_RADIO );\n\n        NRF_RADIO->MODE  = RADIO_MODE_MODE_Ble_1Mbit << RADIO_MODE_MODE_Pos;\n\n        NRF_RADIO->PCNF0 =\n            ( 1 << RADIO_PCNF0_S0LEN_Pos ) |\n            ( 8 << RADIO_PCNF0_LFLEN_Pos ) |\n            ( 0 << RADIO_PCNF0_S1LEN_Pos ) |\n            ( encryption_possible\n                ? ( RADIO_PCNF0_S1INCL_Include << RADIO_PCNF0_S1INCL_Pos )\n                : ( RADIO_PCNF0_S1INCL_Automatic << RADIO_PCNF0_S1INCL_Pos ) );\n\n        NRF_RADIO->PCNF1 =\n            ( RADIO_PCNF1_WHITEEN_Enabled << RADIO_PCNF1_WHITEEN_Pos ) |\n            ( RADIO_PCNF1_ENDIAN_Little << RADIO_PCNF1_ENDIAN_Pos ) |\n            ( 3 << RADIO_PCNF1_BALEN_Pos ) |\n            ( 0 << RADIO_PCNF1_STATLEN_Pos );\n\n        NRF_RADIO->TXADDRESS = 0;\n        NRF_RADIO->RXADDRESSES = 1 << 0;\n\n        NRF_RADIO->CRCCNF    =\n            ( RADIO_CRCCNF_LEN_Three << RADIO_CRCCNF_LEN_Pos ) |\n            ( RADIO_CRCCNF_SKIPADDR_Skip << RADIO_CRCCNF_SKIPADDR_Pos );\n\n        // clear all used PPI pre-programmed channels (16.1.1)\n        NRF_PPI->CHENCLR =\n              ( 1 << compare0_txen_ppi_channel )\n            | ( 1 << compare0_rxen_ppi_channel )\n            | ( 1 << compare1_disable_ppi_channel )\n            | ( 1 << radio_end_capture2_ppi_channel )\n            | ( 1 << radio_bcmatch_aar_start_channel );\n\n        // The polynomial has the form of x^24 +x^10 +x^9 +x^6 +x^4 +x^3 +x+1\n        NRF_RADIO->CRCPOLY   = 0x100065B;\n\n        // TIFS is only enforced if END_DISABLE and DISABLED_TXEN shortcuts are enabled.\n        NRF_RADIO->TIFS      = 150;\n    }\n\n    static int pdu_gap_required_by_encryption()\n    {\n        return NRF_RADIO->PCNF0 & ( RADIO_PCNF0_S1INCL_Include << RADIO_PCNF0_S1INCL_Pos )\n            ? 1\n            : 0;\n    }\n\n    static void init_timer()\n    {\n        nrf_timer->MODE        = TIMER_MODE_MODE_Timer << TIMER_MODE_MODE_Pos;\n        nrf_timer->BITMODE     = TIMER_BITMODE_BITMODE_32Bit;\n        nrf_timer->PRESCALER   = 4; // resulting in a timer resolution of 1µs\n\n        nrf_timer->TASKS_STOP  = 1;\n        nrf_timer->TASKS_CLEAR = 1;\n        nrf_timer->EVENTS_COMPARE[ 0 ] = 0;\n        nrf_timer->EVENTS_COMPARE[ 1 ] = 0;\n        nrf_timer->EVENTS_COMPARE[ 2 ] = 0;\n        nrf_timer->EVENTS_COMPARE[ 3 ] = 0;\n        nrf_timer->INTENCLR    = 0xffffffff;\n\n        nrf_timer->TASKS_START = 1;\n    }\n\n    // see https://devzone.nordicsemi.com/question/47493/disable-interrupts-and-enable-interrupts-if-they-where-enabled/\n    scheduled_radio_base::lock_guard::lock_guard()\n        : context_( __get_PRIMASK() )\n    {\n        __disable_irq();\n    }\n\n    scheduled_radio_base::lock_guard::~lock_guard()\n    {\n        __set_PRIMASK( context_ );\n    }\n\n    scheduled_radio_base::scheduled_radio_base( adv_callbacks& cbs, std::uint32_t encrypted_area )\n        : callbacks_( cbs )\n        , timeout_( false )\n        , received_( false )\n        , evt_timeout_( false )\n        , end_evt_( false )\n        , wake_up_( 0 )\n        , state_( state::idle )\n        , receive_encrypted_( false )\n        , transmit_encrypted_( false )\n        , encrypted_area_( encrypted_area )\n    {\n        // start high freuquence clock source if not done yet\n        if ( !NRF_CLOCK->EVENTS_HFCLKSTARTED )\n        {\n            NRF_CLOCK->TASKS_HFCLKSTART = 1;\n\n            while ( !NRF_CLOCK->EVENTS_HFCLKSTARTED )\n                ;\n        }\n\n        init_debug();\n        init_radio( encrypted_area_ != 0 );\n        init_timer();\n\n        instance = this;\n\n        NVIC_SetPriority( RADIO_IRQn, 0 );\n        NVIC_ClearPendingIRQ( RADIO_IRQn );\n        NVIC_EnableIRQ( RADIO_IRQn );\n        NVIC_ClearPendingIRQ( TIMER0_IRQn );\n        NVIC_EnableIRQ( TIMER0_IRQn );\n    }\n\n    scheduled_radio_base::scheduled_radio_base( adv_callbacks& cbs )\n        : scheduled_radio_base( cbs, false )\n    {\n    }\n\n    unsigned scheduled_radio_base::frequency_from_channel( unsigned channel ) const\n    {\n        assert( channel < 40 );\n\n        if ( channel <= 10 )\n            return 4 + 2 * channel;\n\n        if ( channel <= 36 )\n            return 6 + 2 * channel;\n\n        if ( channel == 37 )\n            return 2;\n\n        if ( channel == 38 )\n            return 26;\n\n        return 80;\n    }\n\n    static bool identity_resolving_enabled = false;\n\n    void scheduled_radio_base::schedule_advertisment(\n            unsigned                        channel,\n            const link_layer::write_buffer& advertising_data,\n            const link_layer::write_buffer& response_data,\n            link_layer::delta_time          when,\n            const link_layer::read_buffer&  receive )\n    {\n        while ((NRF_RADIO->STATE & RADIO_STATE_STATE_Msk) != RADIO_STATE_STATE_Disabled);\n        assert( ( NRF_RADIO->STATE & RADIO_STATE_STATE_Msk ) == RADIO_STATE_STATE_Disabled );\n        assert( !received_ );\n        assert( !timeout_ );\n        assert( state_ == state::idle );\n        assert( receive.buffer && receive.size >= 2u );\n        assert( response_data.buffer );\n\n        const std::uint8_t  send_size  = std::min< std::size_t >( advertising_data.size, maximum_advertising_pdu_size );\n\n        response_data_       = response_data;\n        receive_buffer_      = receive;\n        receive_buffer_.size = std::min< std::size_t >( receive.size, maximum_advertising_pdu_size );\n\n\n        NRF_RADIO->FREQUENCY   = frequency_from_channel( channel );\n        NRF_RADIO->DATAWHITEIV = channel & 0x3F;\n\n        NRF_RADIO->SHORTS      = RADIO_SHORTS_READY_START_Msk | RADIO_SHORTS_END_DISABLE_Msk | RADIO_SHORTS_DISABLED_RXEN_Msk | RADIO_SHORTS_ADDRESS_BCSTART_Msk;\n        NRF_RADIO->PACKETPTR   = reinterpret_cast< std::uint32_t >( advertising_data.buffer );\n        NRF_RADIO->PCNF1       = ( NRF_RADIO->PCNF1 & ~RADIO_PCNF1_MAXLEN_Msk ) | ( send_size << RADIO_PCNF1_MAXLEN_Pos );\n\n        NRF_RADIO->INTENCLR    = 0xffffffff;\n        nrf_timer->INTENCLR    = 0xffffffff;\n\n        NRF_RADIO->EVENTS_END       = 0;\n        NRF_RADIO->EVENTS_DISABLED  = 0;\n        NRF_RADIO->EVENTS_READY     = 0;\n        NRF_RADIO->EVENTS_ADDRESS   = 0;\n        NRF_RADIO->EVENTS_PAYLOAD   = 0;\n\n        if ( identity_resolving_enabled )\n        {\n            nrf_aar->EVENTS_END         = 0;\n            nrf_aar->EVENTS_RESOLVED    = 0;\n            nrf_aar->EVENTS_NOTRESOLVED = 0;\n\n            nrf_aar->ADDRPTR = reinterpret_cast< std::uint32_t >( receive_buffer_.buffer ) + connect_addr_offset;\n        }\n\n        NRF_PPI->CHENCLR = ( 1 << compare0_rxen_ppi_channel );\n        NRF_PPI->CHENSET =\n              ( 1 << compare0_txen_ppi_channel )\n            | ( 1 << compare1_disable_ppi_channel )\n            | ( 1 << radio_end_capture2_ppi_channel );\n\n        NRF_RADIO->INTENSET    = RADIO_INTENSET_DISABLED_Msk;\n\n        const std::uint32_t read_timeout = ( send_size + 1 + 4 + 3 ) * 8 + adv_reponse_timeout_us;\n        state_ = state::adv_transmitting;\n\n        if ( when.zero() )\n        {\n            NRF_RADIO->TASKS_TXEN          = 1;\n            nrf_timer->TASKS_CAPTURE[ 1 ]  = 1;\n            nrf_timer->CC[ 1 ]            += read_timeout + us_radio_tx_startup_time;\n        }\n        else\n        {\n            nrf_timer->EVENTS_COMPARE[ 0 ] = 0;\n            nrf_timer->CC[ 0 ]             = when.usec() - us_radio_tx_startup_time + anchor_offset_.usec();\n            nrf_timer->CC[ 1 ]             = nrf_timer->CC[ 0 ] + us_radio_tx_startup_time + read_timeout;\n            nrf_timer->CC[ 2 ]             = 0;\n\n            // manually triggering event for timer beeing already behind target time\n            nrf_timer->TASKS_CAPTURE[ 3 ]  = 1;\n\n            // TODO: If timer wrapps, >= will fail!!!\n            if ( nrf_timer->EVENTS_COMPARE[ 0 ] || nrf_timer->CC[ 3 ] >= nrf_timer->CC[ 0 ] )\n            {\n                nrf_timer->TASKS_CLEAR = 1;\n                NRF_RADIO->TASKS_TXEN = 1;\n            }\n        }\n    }\n\n    bool scheduled_radio_base::is_valid_scan_request() const\n    {\n        static constexpr std::uint8_t scan_request_size     = 12;\n        static constexpr std::uint8_t scan_request_pdu_type = 0x03;\n        static constexpr std::uint8_t pdu_type_mask         = 0x0F;\n        static constexpr int          pdu_header_size       = 2;\n        static constexpr int          addr_size             = 6;\n        static constexpr std::uint8_t tx_add_mask           = 0x40;\n        static constexpr std::uint8_t rx_add_mask           = 0x80;\n\n        if ( identity_resolving_enabled )\n        {\n            while ( !nrf_aar->EVENTS_END )\n                ;\n\n            if ( nrf_aar->EVENTS_NOTRESOLVED )\n                return false;\n        }\n\n        if ( receive_buffer_.buffer[ 1 ] != scan_request_size )\n            return false;\n\n        if ( ( receive_buffer_.buffer[ 0 ] & pdu_type_mask ) != scan_request_pdu_type )\n            return false;\n\n        const int pdu_gap = pdu_gap_required_by_encryption();\n\n        if ( !std::equal( &receive_buffer_.buffer[ pdu_header_size + addr_size + pdu_gap ], &receive_buffer_.buffer[ pdu_header_size + 2 * addr_size + pdu_gap ],\n            &response_data_.buffer[ pdu_header_size + pdu_gap ] ) )\n            return false;\n\n        // in the scan request, the randomness is stored in RxAdd, in the scan response, it's stored in\n        // TxAdd.\n        const bool scanner_addres_is_random = response_data_.buffer[ 0 ] & tx_add_mask;\n        if ( !static_cast< bool >( receive_buffer_.buffer[ 0 ] & rx_add_mask ) == scanner_addres_is_random )\n            return false;\n\n        const link_layer::device_address scanner( &receive_buffer_.buffer[ pdu_header_size + pdu_gap ], scanner_addres_is_random );\n\n        return callbacks_.is_scan_request_in_filter_callback( scanner );\n    }\n\n    void scheduled_radio_base::stop_radio()\n    {\n        NRF_RADIO->SHORTS        = 0;\n        NRF_RADIO->TASKS_DISABLE = 1;\n\n        state_      = state::idle;\n    }\n\n    void scheduled_radio_base::adv_radio_interrupt()\n    {\n        if ( NRF_RADIO->EVENTS_DISABLED )\n        {\n            NRF_RADIO->EVENTS_DISABLED = 0;\n\n            if ( state_ == state::adv_transmitting )\n            {\n                NRF_RADIO->SHORTS      = RADIO_SHORTS_READY_START_Msk | RADIO_SHORTS_END_DISABLE_Msk | RADIO_SHORTS_DISABLED_TXEN_Msk;\n\n                NRF_RADIO->PACKETPTR   = reinterpret_cast< std::uint32_t >( receive_buffer_.buffer );\n                NRF_RADIO->PCNF1       = ( NRF_RADIO->PCNF1 & ~RADIO_PCNF1_MAXLEN_Msk ) | ( receive_buffer_.size << RADIO_PCNF1_MAXLEN_Pos );\n\n                state_ = state::adv_receiving;\n            }\n            else if ( state_ == state::adv_receiving )\n            {\n                // the anchor is the end of the connect request. The timer was captured with the radio end event\n                anchor_offset_ = link_layer::delta_time( nrf_timer->CC[ 2 ] );\n\n                // either we realy received something, or the timer disabled the radio.\n                if ( ( NRF_RADIO->CRCSTATUS & RADIO_CRCSTATUS_CRCSTATUS_Msk ) == RADIO_CRCSTATUS_CRCSTATUS_CRCOk && NRF_RADIO->EVENTS_PAYLOAD )\n                {\n                    NRF_RADIO->SHORTS = RADIO_SHORTS_READY_START_Msk | RADIO_SHORTS_END_DISABLE_Msk;\n\n                    // stop the timer from canceling the read!\n                    NRF_PPI->CHENCLR  = ( 1 << compare0_txen_ppi_channel )\n                                      | ( 1 << compare1_disable_ppi_channel )\n                                      | ( 1 << radio_end_capture2_ppi_channel );\n\n                    if ( is_valid_scan_request() )\n                    {\n                        state_ = state::adv_transmitting_response;\n\n                        NRF_RADIO->PACKETPTR   = reinterpret_cast< std::uint32_t >( response_data_.buffer );\n                        NRF_RADIO->PCNF1       = ( NRF_RADIO->PCNF1 & ~RADIO_PCNF1_MAXLEN_Msk ) | ( response_data_.size << RADIO_PCNF1_MAXLEN_Pos );\n                    }\n                    else\n                    {\n                        stop_radio();\n                        received_   = true;\n                    }\n                }\n                else\n                {\n                    stop_radio();\n                    timeout_    = true;\n                }\n            }\n            else if ( state_ == state::adv_transmitting_response )\n            {\n                stop_radio();\n                timeout_    = true;\n            }\n\n            NRF_RADIO->EVENTS_PAYLOAD = 0;\n        }\n    }\n\n    void scheduled_radio_base::adv_timer_interrupt()\n    {\n    }\n\n    void scheduled_radio_base::configure_encryption( bool receive, bool transmit )\n    {\n        receive_encrypted_ = receive;\n        transmit_encrypted_ = transmit;\n    }\n\n    static struct alignas( 4 ) ccm_data_struct_t {\n        std::uint8_t data[ 33 ];\n    } ccm_data_struct;\n\n    // hack to be able to reset the CCM with every connection event\n    static std::uint32_t scratch_area_save;\n\n    link_layer::delta_time scheduled_radio_base::start_connection_event_impl(\n        unsigned                        channel,\n        bluetoe::link_layer::delta_time start_receive,\n        bluetoe::link_layer::delta_time end_receive,\n        const link_layer::read_buffer&  receive_buffer )\n    {\n        while ((NRF_RADIO->STATE & RADIO_STATE_STATE_Msk) != RADIO_STATE_STATE_Disabled)\n            ;\n\n        // Stop all interrupts so that the calculation, that enough CPU time is available to setup everything, will not\n        // be disturbed by any interrupt.\n        lock_guard lock;\n\n        assert( ( NRF_RADIO->STATE & RADIO_STATE_STATE_Msk ) == RADIO_STATE_STATE_Disabled );\n        assert( state_ == state::idle );\n        assert( receive_buffer.buffer && receive_buffer.size >= 2u || receive_buffer.empty() );\n        assert( start_receive < end_receive );\n\n        nrf_timer->TASKS_CAPTURE[ 3 ] = 1;\n        const std::uint32_t now   = nrf_timer->CC[ 3 ];\n        const std::uint32_t start_event = start_receive.usec() + anchor_offset_.usec() - us_radio_rx_startup_time;\n        const std::uint32_t end_event   = end_receive.usec() + anchor_offset_.usec() + 500; // TODO: 500: must depend on receive size.\n\n        if ( now + setup_connection_event_limit_us > start_event )\n        {\n            evt_timeout_ = true;\n            return link_layer::delta_time();\n        }\n\n        state_                  = state::evt_wait_connect;\n        receive_buffer_         = receive_buffer.empty()\n            ? link_layer::read_buffer{ &empty_receive_[ 0 ], sizeof( empty_receive_ ) }\n            : receive_buffer;\n\n        NRF_RADIO->FREQUENCY   = frequency_from_channel( channel );\n        NRF_RADIO->DATAWHITEIV = channel & 0x3F;\n\n        NRF_RADIO->INTENCLR    = 0xffffffff;\n        nrf_timer->INTENCLR    = 0xffffffff;\n\n        NRF_RADIO->EVENTS_END       = 0;\n        NRF_RADIO->EVENTS_DISABLED  = 0;\n        NRF_RADIO->EVENTS_READY     = 0;\n        NRF_RADIO->EVENTS_ADDRESS   = 0;\n        NRF_RADIO->EVENTS_CRCERROR  = 0;\n\n        nrf_timer->EVENTS_COMPARE[ 0 ] = 0;\n        nrf_timer->EVENTS_COMPARE[ 1 ] = 0;\n        nrf_timer->EVENTS_COMPARE[ 2 ] = 0;\n\n        if ( receive_encrypted_ )\n        {\n            nrf_radio->PCNF1  = ( NRF_RADIO->PCNF1 & ~RADIO_PCNF1_MAXLEN_Msk )\n                | ( ( receive_buffer_.size + encryption_mic_size ) << RADIO_PCNF1_MAXLEN_Pos );\n\n            // Reseting the CCM before every connection event seems to workaround a bug that\n            // Causes the CCM to start decrypting an incomming PDU, before it was actually received\n            // which causes overwriting the receive buffer, if the length field in the encrypted_area_\n            // was long enough.\n            // (https://devzone.nordicsemi.com/f/nordic-q-a/43656/what-causes-decryption-before-receiving)\n            nrf_ccm->ENABLE = CCM_ENABLE_ENABLE_Disabled;\n            nrf_ccm->ENABLE = CCM_ENABLE_ENABLE_Enabled;\n            nrf_ccm->MODE   =\n                  ( CCM_MODE_MODE_Decryption << CCM_MODE_MODE_Pos )\n                | ( CCM_MODE_LENGTH_Extended << CCM_MODE_LENGTH_Pos );\n            nrf_ccm->CNFPTR = reinterpret_cast< std::uintptr_t >( &ccm_data_struct );\n            nrf_ccm->INPTR = encrypted_area_;\n            nrf_ccm->OUTPTR = reinterpret_cast< std::uint32_t >( receive_buffer_.buffer );\n            nrf_ccm->SCRATCHPTR = scratch_area_save;\n            nrf_ccm->SHORTS = 0;\n            nrf_ccm->EVENTS_ENDKSGEN = 0;\n            nrf_ccm->EVENTS_ENDCRYPT = 0;\n            nrf_ccm->EVENTS_ERROR = 0;\n            nrf_radio->PACKETPTR = encrypted_area_;\n        }\n        else\n        {\n            nrf_radio->PCNF1       = ( NRF_RADIO->PCNF1 & ~RADIO_PCNF1_MAXLEN_Msk ) | ( receive_buffer_.size << RADIO_PCNF1_MAXLEN_Pos );\n\n            nrf_radio->PACKETPTR   = reinterpret_cast< std::uint32_t >( receive_buffer_.buffer );\n        }\n\n        // the hardware is wired to:\n        // - start the receiving part of the radio, when the timer is equal to CC[ 0 ] (compare0_rxen_ppi_channel)\n        // - when the radio ramped up for receiving, the receiving starts              (RADIO_SHORTS_READY_START_Msk)\n        // - when the PDU was receieved, the timer value is captured in CC[ 2 ]        (radio_end_capture2_ppi_channel)\n        // - when a PDU is received, the radio is stopped                              (RADIO_SHORTS_END_DISABLE_Msk)\n        // - if no PDU is received, and the timer reaches CC[ 1 ], the radio is stopped(compare1_disable_ppi_channel)\n        nrf_radio->SHORTS      = RADIO_SHORTS_READY_START_Msk | RADIO_SHORTS_END_DISABLE_Msk | RADIO_SHORTS_DISABLED_TXEN_Msk;\n        nrf_ccm->SHORTS        = 0;\n\n        if ( receive_encrypted_ )\n        {\n            NRF_PPI->CHENCLR =\n                  ( 1 << compare0_txen_ppi_channel )\n                | ( 1 << radio_bcmatch_aar_start_channel );\n\n            NRF_PPI->CHENSET =\n                ( 1 << radio_address_ccm_crypt )\n              | ( 1 << compare0_rxen_ppi_channel )\n              | ( 1 << compare1_disable_ppi_channel )\n              | ( 1 << radio_end_capture2_ppi_channel );\n\n            nrf_ccm->TASKS_KSGEN = 1;\n            NRF_GPIOTE->TASKS_SET[ 1 ] = 1;\n        }\n        else\n        {\n            NRF_PPI->CHENCLR =\n                  ( 1 << compare0_txen_ppi_channel )\n                | ( 1 << compare0_rxen_ppi_channel )\n                | ( 1 << compare1_disable_ppi_channel )\n                | ( 1 << radio_end_capture2_ppi_channel )\n                | ( 1 << radio_address_ccm_crypt )\n                | ( 1 << radio_bcmatch_aar_start_channel );\n\n            NRF_PPI->CHENSET       =\n                  ( 1 << compare0_rxen_ppi_channel )\n                | ( 1 << compare1_disable_ppi_channel )\n                | ( 1 << radio_end_capture2_ppi_channel );\n        }\n\n\n        nrf_radio->INTENSET    = RADIO_INTENSET_DISABLED_Msk;\n\n        nrf_timer->CC[ 0 ] = start_event;\n        nrf_timer->CC[ 1 ] = end_event;\n\n        return link_layer::delta_time::usec( nrf_timer->CC[ 0 ] - now );\n    }\n\n    void scheduled_radio_base::evt_radio_interrupt()\n    {\n        assert( nrf_radio->EVENTS_DISABLED );\n\n        nrf_radio->EVENTS_DISABLED = 0;\n        nrf_radio->EVENTS_READY    = 0;\n\n        if ( state_ == state::evt_wait_connect )\n        {\n            // no need to disable the radio via the timer anymore:\n            NRF_PPI->CHENCLR = ( 1 << radio_end_capture2_ppi_channel )\n                             | ( 1 << compare1_disable_ppi_channel )\n                             | ( 1 << radio_address_ccm_crypt );\n\n            // Transmission has been startet already, make sure, radio gets disabled\n            nrf_radio->SHORTS = RADIO_SHORTS_READY_START_Msk | RADIO_SHORTS_END_DISABLE_Msk;\n\n            /*\n             * There is a special handling for the case, where the CRC is correct, but the MIC fails:\n             * It is expected, that this happens, if the central did not received the last PDU and thus\n             * resends its PDU, while the local receive counter was incremented.\n             */\n            const bool timeout   = nrf_timer->EVENTS_COMPARE[ 1 ];\n            const bool crc_error = !timeout && ( nrf_radio->CRCSTATUS & RADIO_CRCSTATUS_CRCSTATUS_Msk ) != RADIO_CRCSTATUS_CRCSTATUS_CRCOk;\n            const bool mic_error = receive_encrypted_ && receive_buffer_.buffer[ 1 ] != 0 && ( nrf_ccm->MICSTATUS & CCM_MICSTATUS_MICSTATUS_Msk ) == CCM_MICSTATUS_MICSTATUS_CheckFailed;\n            const bool bus_error = receive_encrypted_ && nrf_ccm->EVENTS_ERROR;\n            const bool not_decrypt = receive_encrypted_ && receive_buffer_.buffer[ 1 ] != 0 && nrf_ccm->EVENTS_ENDCRYPT == 0;\n            const bool receive_error = timeout || crc_error || bus_error || not_decrypt;\n\n            if ( !receive_error )\n            {\n                // switch to transmission\n                const auto trans = ( receive_buffer_.buffer == &empty_receive_[ 0 ] || mic_error )\n                    ? callbacks_.next_transmit()\n                    : callbacks_.received_data( receive_buffer_ );\n\n                // Hack to disable the more data flag, because this radio implementation is currently\n                // not able to do this (but it should be possible with the given hardware).\n                const_cast< std::uint8_t* >( trans.buffer )[ 0 ] = trans.buffer[ 0 ] & ~more_data_flag;\n\n                if ( transmit_encrypted_ && trans.buffer[ 1 ] != 0 )\n                {\n                    callbacks_.load_transmit_counter();\n\n                    nrf_radio->PACKETPTR = encrypted_area_;\n\n                    nrf_ccm->SHORTS  = CCM_SHORTS_ENDKSGEN_CRYPT_Msk;\n                    nrf_ccm->MODE    =\n                          ( CCM_MODE_MODE_Encryption << CCM_MODE_MODE_Pos )\n                        | ( CCM_MODE_LENGTH_Extended << CCM_MODE_LENGTH_Pos );\n                    nrf_ccm->OUTPTR  = encrypted_area_;\n                    nrf_ccm->INPTR   = reinterpret_cast< std::uint32_t >( trans.buffer );\n                    nrf_ccm->SCRATCHPTR  = scratch_area_save;\n\n                    nrf_radio->PCNF1 = ( nrf_radio->PCNF1 & ~RADIO_PCNF1_MAXLEN_Msk ) | ( ( trans.size + encryption_mic_size )<< RADIO_PCNF1_MAXLEN_Pos );\n\n                    nrf_ccm->EVENTS_ENDKSGEN    = 0;\n                    nrf_ccm->EVENTS_ENDCRYPT    = 0;\n                    nrf_ccm->TASKS_KSGEN        = 1;\n                    NRF_GPIOTE->TASKS_SET[ 1 ]  = 1;\n                }\n                else\n                {\n                    nrf_radio->PACKETPTR   = reinterpret_cast< std::uint32_t >( trans.buffer );\n                    NRF_PPI->CHENCLR = ( 1 << radio_address_ccm_crypt );\n                    nrf_radio->PCNF1 = ( nrf_radio->PCNF1 & ~RADIO_PCNF1_MAXLEN_Msk ) | ( trans.size << RADIO_PCNF1_MAXLEN_Pos );\n                }\n\n\n                state_   = state::evt_transmiting_closing;\n\n                // the timer was captured with the end event; the anchor is the start of the receiving.\n                // Additional to the ll PDU length there are 1 byte preamble, 4 byte access address, 2 byte LL header and 3 byte crc.\n                // In case, that the message was encrypted, there was a 4 byte MIC appended.\n                static constexpr std::size_t ll_pdu_overhead = 1 + 4 + 2 + 3;\n                std::size_t total_pdu_length = receive_buffer_.buffer[ 1 ] + ll_pdu_overhead;\n\n                if ( receive_encrypted_ && receive_buffer_.buffer[ 1 ] )\n                    total_pdu_length += encryption_mic_size;\n\n                anchor_offset_ = link_layer::delta_time( nrf_timer->CC[ 2 ] - total_pdu_length * 8 );\n            }\n            else\n            {\n                nrf_ccm->OUTPTR  = 0;\n                nrf_ccm->INPTR   = 0;\n                nrf_radio->PACKETPTR = 0;\n\n                nrf_ccm->EVENTS_ERROR    = 0;\n                nrf_ccm->SHORTS          = 0;\n\n                NRF_PPI->CHENCLR =\n                      ( 1 << compare0_txen_ppi_channel )\n                    | ( 1 << compare0_rxen_ppi_channel )\n                    | ( 1 << compare1_disable_ppi_channel )\n                    | ( 1 << radio_end_capture2_ppi_channel )\n                    | ( 1 << radio_address_ccm_crypt );\n\n                NRF_RADIO->SHORTS        = 0;\n                NRF_RADIO->TASKS_STOP    = 1;\n                NRF_RADIO->TASKS_DISABLE = 1;\n                nrf_ccm->TASKS_STOP      = 1;\n\n                state_       = state::idle;\n                evt_timeout_ = true;\n            }\n        }\n        else if ( state_ == state::evt_transmiting_closing )\n        {\n            nrf_ccm->OUTPTR  = 0;\n            nrf_ccm->INPTR   = 0;\n            nrf_radio->PACKETPTR = 0;\n\n            state_   = state::idle;\n            end_evt_ = true;\n        }\n        else\n        {\n            assert( !\"unrecognized radio state!\" );\n        }\n    }\n\n    void scheduled_radio_base::evt_timer_interrupt()\n    {\n    }\n\n    void scheduled_radio_base::radio_interrupt()\n    {\n        if ( static_cast< unsigned >( state_ ) >= connection_event_type_base )\n        {\n            evt_radio_interrupt();\n        }\n        else\n        {\n            adv_radio_interrupt();\n        }\n\n    }\n\n    void scheduled_radio_base::timer_interrupt()\n    {\n        if ( static_cast< unsigned >( state_ ) >= connection_event_type_base )\n        {\n            evt_timer_interrupt();\n        }\n        else\n        {\n            adv_timer_interrupt();\n        }\n    }\n\n    void scheduled_radio_base::set_access_address_and_crc_init( std::uint32_t access_address, std::uint32_t crc_init )\n    {\n        NRF_RADIO->BASE0     = ( access_address << 8 ) & 0xFFFFFF00;\n        NRF_RADIO->PREFIX0   = ( access_address >> 24 ) & RADIO_PREFIX0_AP0_Msk;\n        NRF_RADIO->CRCINIT   = crc_init;\n    }\n\n    void scheduled_radio_base::run()\n    {\n        while ( !received_ && !timeout_ && !evt_timeout_ && !end_evt_ && wake_up_ == 0 )\n            __WFI();\n\n        if ( received_ )\n        {\n            assert( reinterpret_cast< std::uint8_t* >( NRF_RADIO->PACKETPTR ) == receive_buffer_.buffer );\n\n            receive_buffer_.size = std::min< std::size_t >(\n                receive_buffer_.size,\n                ( receive_buffer_.buffer[ 1 ] & 0x3f ) + 2 + pdu_gap_required_by_encryption()\n            );\n            received_ = false;\n\n            callbacks_.adv_received( receive_buffer_ );\n        }\n\n        if ( timeout_ )\n        {\n            timeout_ = false;\n            callbacks_.adv_timeout();\n        }\n\n        if ( evt_timeout_ )\n        {\n            evt_timeout_ = false;\n            callbacks_.timeout();\n        }\n\n        if ( end_evt_ )\n        {\n            end_evt_ = false;\n            callbacks_.end_event();\n        }\n\n        if ( wake_up_ )\n        {\n            --wake_up_;\n        }\n    }\n\n    void scheduled_radio_base::wake_up()\n    {\n        ++wake_up_;\n    }\n\n    std::uint32_t scheduled_radio_base::static_random_address_seed() const\n    {\n        return NRF_FICR->DEVICEID[ 0 ];\n    }\n\n    void scheduled_radio_base::nrf_flash_memory_access_begin()\n    {\n        lock_guard lock;\n\n        nrf_ccm->OUTPTR  = 0;\n        nrf_ccm->INPTR   = 0;\n        nrf_radio->PACKETPTR = 0;\n\n        nrf_ccm->EVENTS_ERROR    = 0;\n        nrf_ccm->SHORTS          = 0;\n\n        NRF_PPI->CHENCLR =\n              ( 1 << compare0_txen_ppi_channel )\n            | ( 1 << compare0_rxen_ppi_channel )\n            | ( 1 << compare1_disable_ppi_channel )\n            | ( 1 << radio_end_capture2_ppi_channel )\n            | ( 1 << radio_address_ccm_crypt );\n\n        NRF_RADIO->SHORTS        = 0;\n        NRF_RADIO->TASKS_STOP    = 1;\n        NRF_RADIO->TASKS_DISABLE = 1;\n        nrf_ccm->TASKS_STOP      = 1;\n\n        state_       = state::idle;\n    }\n\n    void scheduled_radio_base::nrf_flash_memory_access_end()\n    {\n        // this kicks the CPU out of the loop in run() and requests the link layer to setup the next connection event\n        evt_timeout_ = true;\n    }\n\n    /*\n     * With encryption\n     */\n\n    // simply for easier debugging\n    static NRF_RNG_Type* const          nrf_random  = NRF_RNG;\n    static NRF_ECB_Type* const          nrf_aes     = NRF_ECB;\n\n    static std::uint8_t random_number8()\n    {\n        nrf_random->TASKS_START = 1;\n\n        while ( !nrf_random->EVENTS_VALRDY )\n            ;\n\n        nrf_random->EVENTS_VALRDY = 0;\n\n        return nrf_random->VALUE;\n    }\n\n    static std::uint16_t random_number16()\n    {\n        return static_cast< std::uint16_t >( random_number8() )\n            | ( static_cast< std::uint16_t >( random_number8() ) << 8 );\n    }\n\n    static std::uint32_t random_number32()\n    {\n        return static_cast< std::uint32_t >( random_number16() )\n            | ( static_cast< std::uint32_t >( random_number16() ) << 16 );\n    }\n\n    static std::uint64_t random_number64()\n    {\n        return static_cast< std::uint64_t >( random_number32() )\n            | ( static_cast< std::uint64_t >( random_number32() ) << 32 );\n    }\n\n    static constexpr std::size_t ccm_key_offset = 0;\n    static constexpr std::size_t ccm_packet_counter_offset = 16;\n    static constexpr std::size_t ccm_packet_counter_size   = 5;\n    static constexpr std::size_t ccm_direction_offset = 24;\n    static constexpr std::size_t ccm_iv_offset = 25;\n\n    static constexpr std::uint8_t central_to_peripheral_ccm_direction = 0x01;\n    static constexpr std::uint8_t peripheral_to_central_ccm_direction = 0x00;\n\n    static void init_ccm_data_structure( std::uint32_t scratch_area )\n    {\n        scratch_area_save   = scratch_area;\n        nrf_ccm->SCRATCHPTR = scratch_area;\n        nrf_ccm->CNFPTR     = reinterpret_cast< std::uintptr_t >( &ccm_data_struct );\n    }\n\n    // Note: While every function above the link layer uses low to high byte order inputs to the\n    // EAS function, the CCM, that encrypts the link layer trafic, uses high to low byte order.\n    // That's why the intput and output in aes_le() changeing the byte order. The result of the\n    // key deversification is the key for the CCM algorithm and thus have to be stored in high to\n    // low byte order.\n\n    static void setup_ccm_data_structure( const bluetoe::details::uint128_t& key, std::uint64_t IV )\n    {\n        std::copy( key.rbegin(), key.rend(), &ccm_data_struct.data[ ccm_key_offset ] );\n        std::fill( &ccm_data_struct.data[ ccm_packet_counter_offset ],\n            &ccm_data_struct.data[ ccm_packet_counter_offset + ccm_packet_counter_size ], 0 );\n\n        details::write_64bit( &ccm_data_struct.data[ ccm_iv_offset ], IV );\n    }\n\n    static bluetoe::details::uint128_t aes_le( const bluetoe::details::uint128_t& key, const std::uint8_t* data )\n    {\n        static struct alignas( 4 ) ecb_data_t {\n            std::uint8_t data[ 3 * 16 ];\n        } ecb_scratch_data;\n\n        nrf_aes->ECBDATAPTR = reinterpret_cast< std::uint32_t >( &ecb_scratch_data.data[ 0 ] );\n\n        std::copy( key.rbegin(), key.rend(), &ecb_scratch_data.data[ 0 ] );\n        std::reverse_copy( data, data + 16, &ecb_scratch_data.data[ 16 ] );\n\n        nrf_aes->TASKS_STARTECB = 1;\n\n        while ( !nrf_aes->EVENTS_ENDECB && !nrf_aes->EVENTS_ERRORECB )\n            ;\n\n        assert( !nrf_aes->EVENTS_ERRORECB );\n        nrf_aes->EVENTS_ENDECB = 0;\n\n        bluetoe::details::uint128_t result;\n        std::copy( &ecb_scratch_data.data[ 32 ], &ecb_scratch_data.data[ 48 ], result.rbegin() );\n\n        // erase key out of memory\n        std::fill( &ecb_scratch_data.data[ 0 ], &ecb_scratch_data.data[ 16 ], 0 );\n\n        return result;\n    }\n\n    static bluetoe::details::uint128_t aes_le( const bluetoe::details::uint128_t& key, const bluetoe::details::uint128_t& data )\n    {\n        return aes_le( key, data.data() );\n    }\n\n    static bluetoe::details::uint128_t xor_( bluetoe::details::uint128_t a, const std::uint8_t* b )\n    {\n        std::transform(\n            a.begin(), a.end(),\n            b,\n            a.begin(),\n            []( std::uint8_t a, std::uint8_t b ) -> std::uint8_t\n            {\n                return a xor b;\n            }\n        );\n\n        return a;\n    }\n\n    static bluetoe::details::uint128_t xor_( bluetoe::details::uint128_t a, const bluetoe::details::uint128_t& b )\n    {\n        return xor_( a, b.data() );\n    }\n\n    scheduled_radio_base_with_encryption_base::scheduled_radio_base_with_encryption_base(\n        adv_callbacks& cbs, std::uint32_t scratch_area, std::uint32_t encrypted_area )\n        : scheduled_radio_base( cbs, encrypted_area )\n    {\n        nrf_random->CONFIG = RNG_CONFIG_DERCEN_Msk;\n        nrf_random->SHORTS = RNG_SHORTS_VALRDY_STOP_Msk;\n\n        init_ccm_data_structure( scratch_area );\n    }\n\n    details::uint128_t scheduled_radio_base_with_encryption_base::create_srand()\n    {\n        details::uint128_t result;\n        std::generate( result.begin(), result.end(), random_number8 );\n\n        return result;\n    }\n\n    details::longterm_key_t scheduled_radio_base_with_encryption_base::create_long_term_key()\n    {\n        const details::longterm_key_t result = {\n            create_srand(),\n            random_number64(),\n            random_number16()\n        };\n\n        return result;\n    }\n\n    details::uint128_t scheduled_radio_base_with_encryption_base::c1(\n        const bluetoe::details::uint128_t& temp_key,\n        const bluetoe::details::uint128_t& rand,\n        const bluetoe::details::uint128_t& p1,\n        const bluetoe::details::uint128_t& p2 ) const\n    {\n        // c1 (k, r, preq, pres, iat, rat, ia, ra) = e(k, e(k, r XOR p1) XOR p2)\n        const auto p1_ = aes_le( temp_key, xor_( rand, p1 ) );\n\n        return aes_le( temp_key, xor_( p1_, p2 ) );\n    }\n\n    bluetoe::details::uint128_t scheduled_radio_base_with_encryption_base::s1(\n        const bluetoe::details::uint128_t& temp_key,\n        const bluetoe::details::uint128_t& srand,\n        const bluetoe::details::uint128_t& mrand )\n    {\n        bluetoe::details::uint128_t r;\n        std::copy( &srand[ 0 ], &srand[ 8 ], &r[ 8 ] );\n        std::copy( &mrand[ 0 ], &mrand[ 8 ], &r[ 0 ] );\n\n        return aes_le( temp_key, r );\n    }\n\n    bool scheduled_radio_base_with_encryption_base::is_valid_public_key( const std::uint8_t* public_key ) const\n    {\n        bluetoe::details::ecdh_public_key_t key;\n        std::reverse_copy(public_key, public_key + 32, key.begin());\n        std::reverse_copy(public_key + 32, public_key + 64, key.begin() + 32);\n\n        return uECC_valid_public_key( key.data() );\n    }\n\n    std::pair< bluetoe::details::ecdh_public_key_t, bluetoe::details::ecdh_private_key_t > scheduled_radio_base_with_encryption_base::generate_keys()\n    {\n        uECC_set_rng( []( uint8_t *dest, unsigned size )->int {\n            std::generate( dest, dest + size, random_number8 );\n\n            return 1;\n        } );\n\n        bluetoe::details::ecdh_public_key_t  public_key;\n        bluetoe::details::ecdh_private_key_t private_key;\n\n        const auto rc = uECC_make_key( public_key.data(), private_key.data() );\n        static_cast< void >( rc );\n        assert( rc == 1 );\n\n        std::reverse( public_key.begin(), public_key.begin() + 32 );\n        std::reverse( public_key.begin() + 32, public_key.end() );\n        std::reverse( private_key.begin(), private_key.end() );\n\n        return { public_key, private_key };\n    }\n\n    bluetoe::details::uint128_t scheduled_radio_base_with_encryption_base::select_random_nonce()\n    {\n        bluetoe::details::uint128_t result;\n        std::generate( result.begin(), result.end(), random_number8 );\n\n        return result;\n    }\n\n    bluetoe::details::ecdh_shared_secret_t scheduled_radio_base_with_encryption_base::p256( const std::uint8_t* private_key, const std::uint8_t* public_key )\n    {\n        bluetoe::details::ecdh_private_key_t shared_secret;\n        bluetoe::details::ecdh_private_key_t priv_key;\n        bluetoe::details::ecdh_public_key_t  pub_key;\n        std::reverse_copy( public_key, public_key + 32, pub_key.begin() );\n        std::reverse_copy( public_key + 32, public_key + 64, pub_key.begin() + 32 );\n        std::reverse_copy( private_key, private_key + 32, priv_key.begin() );\n\n        const int rc = uECC_shared_secret( pub_key.data(), priv_key.data(), shared_secret.data() );\n        static_cast< void >( rc );\n        assert( rc == 1 );\n\n        bluetoe::details::ecdh_shared_secret_t result;\n        std::reverse_copy( shared_secret.begin(), shared_secret.end(), result.begin() );\n\n        return result;\n    }\n\n    static bluetoe::details::uint128_t left_shift(const bluetoe::details::uint128_t& input)\n    {\n        bluetoe::details::uint128_t output;\n\n        std::uint8_t overflow = 0;\n        for ( std::size_t i = 0; i != input.size(); ++i )\n        {\n            output[ i ] = ( input[i] << 1 ) | overflow;\n            overflow = ( input[ i ] & 0x80 ) ? 1 : 0;\n        }\n\n        return output;\n    }\n\n    static bluetoe::details::uint128_t aes_cmac_k1_subkey_generation( const bluetoe::details::uint128_t& key )\n    {\n        const bluetoe::details::uint128_t zero = {{ 0x00 }};\n        const bluetoe::details::uint128_t C    = {{ 0x87 }};\n\n        const bluetoe::details::uint128_t k0 = aes_le( key, zero );\n\n        const bluetoe::details::uint128_t k1 = ( k0.back() & 0x80 ) == 0\n            ? left_shift(k0)\n            : xor_( left_shift(k0), C );\n\n        return k1;\n    }\n\n    static bluetoe::details::uint128_t aes_cmac_k2_subkey_generation( const bluetoe::details::uint128_t& key )\n    {\n        const bluetoe::details::uint128_t C    = {{ 0x87 }};\n\n        const bluetoe::details::uint128_t k1 = aes_cmac_k1_subkey_generation( key );\n        const bluetoe::details::uint128_t k2 = ( k1.back() & 0x80 ) == 0\n            ? left_shift(k1)\n            : xor_( left_shift(k1), C );\n\n        return k2;\n    }\n\n    bluetoe::details::uint128_t scheduled_radio_base_with_encryption_base::f4( const std::uint8_t* u, const std::uint8_t* v, const std::array< std::uint8_t, 16 >& k, std::uint8_t z )\n    {\n        const bluetoe::details::uint128_t m4 = {{\n            0x00, 0x00, 0x00, 0x00,\n            0x00, 0x00, 0x00, 0x00,\n            0x00, 0x00, 0x00, 0x00,\n            0x00, 0x00, 0x80, z\n        }};\n\n        auto t0 = aes_le( k, &u[16] );\n        auto t1 = aes_le( k, xor_( t0, &u[0] ) );\n        auto t2 = aes_le( k, xor_( t1, &v[16] ) );\n        auto t3 = aes_le( k, xor_( t2, &v[0] ) );\n\n        return aes_le( k, xor_( t3, xor_( aes_cmac_k2_subkey_generation( k ), m4 ) ) );\n    }\n\n    static bluetoe::details::uint128_t f5_cmac(\n        const bluetoe::details::uint128_t& key,\n        const std::uint8_t* buffer )\n    {\n        const std::uint8_t* m0 = &buffer[ 48 ];\n        const std::uint8_t* m1 = &buffer[ 32 ];\n        const std::uint8_t* m2 = &buffer[ 16 ];\n        const std::uint8_t* m3 = &buffer[ 0 ];\n\n        auto t0 = aes_le( key, m0 );\n        auto t1 = aes_le( key, xor_( t0, m1 ) );\n        auto t2 = aes_le( key, xor_( t1, m2 ) );\n\n        return aes_le( key, xor_( t2, xor_( aes_cmac_k2_subkey_generation( key ), m3 ) ) );\n    }\n\n    static bluetoe::details::uint128_t f5_key( const bluetoe::details::ecdh_shared_secret_t dh_key )\n    {\n        static const bluetoe::details::uint128_t salt = {{\n            0xBE, 0x83, 0x60, 0x5A, 0xDB, 0x0B, 0x37, 0x60,\n            0x38, 0xA5, 0xF5, 0xAA, 0x91, 0x83, 0x88, 0x6C\n        }};\n\n        auto t0 = aes_le( salt, &dh_key[ 16 ] );\n\n        return aes_le( salt, xor_( t0, xor_( aes_cmac_k1_subkey_generation( salt ), &dh_key[ 0 ] ) ) );\n    }\n\n    std::pair< bluetoe::details::uint128_t, bluetoe::details::uint128_t > scheduled_radio_base_with_encryption_base::f5(\n        const bluetoe::details::ecdh_shared_secret_t dh_key,\n        const bluetoe::details::uint128_t& nonce_central,\n        const bluetoe::details::uint128_t& nonce_periperal,\n        const bluetoe::link_layer::device_address& addr_controller,\n        const bluetoe::link_layer::device_address& addr_peripheral )\n    {\n        // all 4 blocks are allocated in revers order to make it easier to copy data that overlaps\n        // two blocks\n        std::uint8_t buffer[ 64 ] = { 0 };\n\n        static const std::uint8_t m0_fill[] = {\n            0x65, 0x6c, 0x74, 0x62\n        };\n\n        static const std::uint8_t m3_fill[] = {\n            0x80, 0x00, 0x01\n        };\n\n        std::copy( std::begin( m0_fill ), std::end( m0_fill ), &buffer[ 11 + 48 ] );\n        std::copy( std::begin( m3_fill ), std::end( m3_fill ), &buffer[ 10 ] );\n\n        std::copy( nonce_central.begin(), nonce_central.end(), &buffer[ 32 + 11 ] );\n        std::copy( nonce_periperal.begin(), nonce_periperal.end(), &buffer[ 16 + 11 ] );\n\n        buffer[ 16 + 10 ] = addr_controller.is_random() ? 1 : 0;\n        std::copy( addr_controller.begin(), addr_controller.end(), &buffer[ 16 + 4 ] );\n        buffer[ 16 + 3 ] = addr_peripheral.is_random() ? 1 : 0;\n        std::copy( addr_peripheral.begin(), addr_peripheral.end(), &buffer[ 13 ] );\n\n        const bluetoe::details::uint128_t key     = f5_key( dh_key );\n        const bluetoe::details::uint128_t mac_key = f5_cmac( key, buffer );\n        // increment counter\n        buffer[ 15 + 48 ] = 1;\n        const bluetoe::details::uint128_t ltk     = f5_cmac( key, buffer );\n\n        return { mac_key, ltk };\n    }\n\n    bluetoe::details::uint128_t scheduled_radio_base_with_encryption_base::f6(\n        const bluetoe::details::uint128_t& key,\n        const bluetoe::details::uint128_t& n1,\n        const bluetoe::details::uint128_t& n2,\n        const bluetoe::details::uint128_t& r,\n        const bluetoe::details::io_capabilities_t& io_caps,\n        const bluetoe::link_layer::device_address& addr_controller,\n        const bluetoe::link_layer::device_address& addr_peripheral )\n    {\n        std::uint8_t m4_m3[ 32 ] = { 0 };\n\n        std::copy( io_caps.begin(), io_caps.end(), &m4_m3[ 16 + 13 ] );\n        m4_m3[ 16 + 12 ] = addr_controller.is_random() ? 1 : 0;\n        std::copy( addr_controller.begin(), addr_controller.end(), &m4_m3[ 22 ] );\n        m4_m3[ 16 + 5 ] = addr_peripheral.is_random() ? 1 : 0;\n        std::copy( addr_peripheral.begin(), addr_peripheral.end(), &m4_m3[ 15 ] );\n        m4_m3[ 14 ] = 0x80;\n\n        const std::uint8_t* m3 = &m4_m3[ 16 ];\n        const std::uint8_t* m4 = &m4_m3[ 0 ];\n\n        auto t0 = aes_le( key, n1 );\n        auto t1 = aes_le( key, xor_( t0, n2 ) );\n        auto t2 = aes_le( key, xor_( t1, r ) );\n        auto t3 = aes_le( key, xor_( t2, m3 ) );\n\n        return aes_le( key, xor_( t3, xor_( aes_cmac_k2_subkey_generation( key ), m4 ) ) );\n    }\n\n    std::uint32_t scheduled_radio_base_with_encryption_base::g2(\n        const std::uint8_t*                 u,\n        const std::uint8_t*                 v,\n        const bluetoe::details::uint128_t&  x,\n        const bluetoe::details::uint128_t&  y )\n    {\n        auto t0 = aes_le( x, u + 16 );\n        auto t1 = aes_le( x, xor_( t0, u ) );\n        auto t2 = aes_le( x, xor_( t1, v + 16 ) );\n        auto t3 = aes_le( x, xor_( t2, v ) );\n        auto t4 = aes_le( x, xor_( t3, xor_( aes_cmac_k1_subkey_generation( x ), y ) ) );\n\n        return bluetoe::details::read_32bit( t4.begin() );\n    }\n\n    bluetoe::details::uint128_t scheduled_radio_base_with_encryption_base::create_passkey()\n    {\n        const bluetoe::details::uint128_t result{{\n            random_number8(), random_number8(), random_number8()\n        }};\n\n        return result;\n    }\n\n    std::pair< std::uint64_t, std::uint32_t > scheduled_radio_base_with_encryption_base::setup_encryption(\n        bluetoe::details::uint128_t key, std::uint64_t skdm, std::uint32_t ivm )\n    {\n        const std::uint64_t skds = random_number64();\n        const std::uint32_t ivs  = random_number32();\n\n        bluetoe::details::uint128_t session_descriminator;\n        details::write_64bit( &session_descriminator[ 0 ], skdm );\n        details::write_64bit( &session_descriminator[ 8 ], skds );\n\n        setup_ccm_data_structure(\n            aes_le( key, session_descriminator),\n            static_cast< std::uint64_t >( ivm ) | ( static_cast< std::uint64_t >( ivs ) << 32 ) );\n\n        return { skds, ivs };\n    }\n\n    void scheduled_radio_base_with_encryption_base::start_receive_encrypted()\n    {\n        rx_counter_ = counter();\n        nrf_ccm->ENABLE = CCM_ENABLE_ENABLE_Enabled << CCM_ENABLE_ENABLE_Pos;\n        configure_encryption( true, false );\n    }\n\n    void scheduled_radio_base_with_encryption_base::start_transmit_encrypted()\n    {\n        tx_counter_ = counter();\n        configure_encryption( true, true );\n    }\n\n    void scheduled_radio_base_with_encryption_base::stop_receive_encrypted()\n    {\n        configure_encryption( false, true );\n    }\n\n    void scheduled_radio_base_with_encryption_base::stop_transmit_encrypted()\n    {\n        configure_encryption( false, false );\n\n        // remove key from memory\n        std::memset( &ccm_data_struct, 0, sizeof( ccm_data_struct ) );\n        nrf_ccm->ENABLE = nrf_ccm->ENABLE & ~CCM_ENABLE_ENABLE_Msk;\n    }\n\n    void scheduled_radio_base_with_encryption_base::load_receive_packet_counter()\n    {\n        rx_counter_.copy_to( &ccm_data_struct.data[ ccm_packet_counter_offset ] );\n        ccm_data_struct.data[ ccm_direction_offset ] = central_to_peripheral_ccm_direction;\n    }\n\n    void scheduled_radio_base_with_encryption_base::load_transmit_packet_counter()\n    {\n        tx_counter_.copy_to( &ccm_data_struct.data[ ccm_packet_counter_offset ] );\n        ccm_data_struct.data[ ccm_direction_offset ] = peripheral_to_central_ccm_direction;\n    }\n\n    void scheduled_radio_base_with_encryption_base::set_identity_resolving_key( const details::identity_resolving_key_t& irk )\n    {\n        static details::identity_resolving_key_t irk_storage;\n        irk_storage = irk;\n\n        identity_resolving_enabled = true;\n\n        // disable CCM\n        nrf_ccm->ENABLE   = CCM_ENABLE_ENABLE_Disabled;\n        nrf_ccm->INTENCLR = 0xFFFFFFFF;\n        nrf_ppi->CHENCLR  = ( 1 << radio_address_ccm_crypt );\n\n        // setup AAR\n        nrf_ppi->CHENSET    = ( 1 << radio_bcmatch_aar_start_channel );\n        nrf_radio->BCC      = 16 + 2 * ( 6 * 8 );\n        nrf_aar->SCRATCHPTR = scratch_area_save;\n        nrf_aar->IRKPTR     = reinterpret_cast< std::uint32_t >( &irk_storage );\n        nrf_aar->NIRK       = 1;\n\n        nrf_aar->ENABLE     = AAR_ENABLE_ENABLE_Msk;\n    }\n\n} // namespace nrf51_details\n}\n\nextern \"C\" void RADIO_IRQHandler(void)\n{\n    bluetoe::nrf51_details::instance->radio_interrupt();\n}\n\nextern \"C\" void TIMER0_IRQHandler(void)\n{\n    bluetoe::nrf51_details::instance->timer_interrupt();\n}\n"
  },
  {
    "path": "bluetoe/bindings/nordic/nrf52/CMakeLists.txt",
    "content": "add_library(\n    bluetoe_bindings_nrf52\n    STATIC\n    EXCLUDE_FROM_ALL\n    nrf52.cpp\n    security_tool_box.cpp\n)\n\nadd_library(bluetoe::bindings::nrf52 ALIAS bluetoe_bindings_nrf52)\n\ntarget_include_directories(bluetoe_bindings_nrf52\n    PUBLIC\n        include\n)\n\ntarget_link_libraries(bluetoe_bindings_nrf52\n    PUBLIC\n        bluetoe::utility\n        bluetoe::sm\n        bluetoe::iface\n        bluetoe::link_layer\n        bluetoe::bindings::nordic\n    PRIVATE\n        bluetoe::bindings::nrf::uecc\n        toolchain::${BINDING}\n)\n\ntarget_compile_features(bluetoe_bindings_nrf52 INTERFACE cxx_std_11)\ntarget_compile_options(bluetoe_bindings_nrf52 INTERFACE -Wall -pedantic -Wextra -Wfatal-errors -Wno-parentheses)\n"
  },
  {
    "path": "bluetoe/bindings/nordic/nrf52/include/bluetoe/device.hpp",
    "content": "#ifndef BLUETOE_DEVICE_HPP\n#define BLUETOE_DEVICE_HPP\n\n#include <bluetoe/nrf52.hpp>\n\nnamespace bluetoe\n{\n    /**\n     * @brief binding to actual hardware\n     *\n     * @sa nrf52\n     */\n    template < class Server, typename ... Options >\n    using device = typename nrf52_details::link_layer_factory<\n        Server,\n        details::requires_encryption_support_t< Server >::value,\n        typename nrf52_details::radio_options< Options... >::result,\n        typename nrf52_details::link_layer_options< Options... >::result\n    >::link_layer;\n}\n\n#endif //BLUETOE_DEVICE_HPP\n"
  },
  {
    "path": "bluetoe/bindings/nordic/nrf52/include/bluetoe/nrf52.hpp",
    "content": "#ifndef BLUETOE_BINDINGS_NRF52_HPP\n#define BLUETOE_BINDINGS_NRF52_HPP\n\n#include <bluetoe/link_layer.hpp>\n#include <bluetoe/nrf.hpp>\n#include <bluetoe/meta_tools.hpp>\n#include <bluetoe/ll_data_pdu_buffer.hpp>\n#include <bluetoe/security_tool_box.hpp>\n#include <bluetoe/connection_events.hpp>\n\n/**\n * @file nrf52.hpp\n *\n * Design desisions:\n *\n * - The radio interrupt has highes priority\n * - The radio ISR is triggered by the radio DISABLED event.\n * - The radio is either disabled by receiving and transmitting, or by the receive timeout\n *   timer, that triggers the DISABLE task of the radio, if the reception timed out.\n * - The ancor of every timing, is the reception of the first PDU in a connection event.\n * - During advertising, the accuracy of the ancor is not important, as there is already some\n *   random jitter to be applied to the interval according to the specs.\n * - CC[ 0 ] of timer0 is used to start the radio\n * - CC[ 1 ] is used to implement the timeout timer and DISABLES the radio\n * - CC[ 2 ] is used to capture the anchor when receiving a connect request or the first PDU\n *           in a connection event.\n * - RTC0 is always running and used as time base. TIMER0 is just started if the RTC0 comes close\n *   to a connection / advertising event.\n *\n * Resources used:\n *\n * - The radio peripheral is exclusively used by Bluetoe.\n * - Timer0 is exclusively used by Bluetoe.\n * - Timer1 is used by Bluetoe, if the synchronized_connection_event_callback<> feature is used.\n * - Bluetoe will switch the HFXO on and off.\n * - RTC0 is exclusively used by Bluetoe.\n * - Bluetoe will switch on the configured low frequency clock source.\n * - CCM, AES, and RNG peripheral are exclusively used by Bluetoe, if encryption\n *   is enabled.\n * - The highest priority interrupt level is exclusively used by Bluetoe.\n * - Bluetoe used PPI channel 19 exclusively\n * - Bluetoe used PPI channel 18 exclusively, if the synchronized_connection_event_callback<> feature is used.\n */\nnamespace bluetoe\n{\n    namespace nrf52_details\n    {\n        static constexpr std::uint8_t       maximum_advertising_pdu_size = 0x3f;\n        // position of the connecting address (AdvA)\n        static constexpr unsigned           connect_addr_offset          = 2 + 6;\n\n        // after T_IFS (150µs +- 2) at maximum, a connection request will be received (34 Bytes + 1 Byte preable, 4 Bytes Access Address and 3 Bytes CRC)\n        // plus some additional 20µs\n        static constexpr std::uint32_t      adv_reponse_timeout_us       = 152 + 42 * 8 + 20;\n        static constexpr unsigned           us_radio_rx_startup_time     = 140;\n        static constexpr unsigned           us_radio_tx_startup_time     = 130;\n\n        // Time reserved to setup a connection event in µs\n        // time measured to setup a connection event, using GCC 8.3.1 with -O0 is 12µs\n        // the addition 31µs is to take the granularity of the sleep clock into account (32kHz)\n        // a second 31µs is add to take the same granularity of the sleep clock into account when\n        // it is used to calculate the current distance to the last anchor\n        static constexpr std::uint32_t      setup_connection_event_limit_us =\n            50 + std::max( us_radio_rx_startup_time, us_radio_tx_startup_time ) + 31 + 31;\n\n        static constexpr std::uint8_t       more_data_flag = 0x10;\n        static constexpr std::size_t        encryption_mic_size = 4;\n\n        /**\n         * @brief Counter used for CCM\n         */\n        struct counter {\n            std::uint32_t   low;\n            std::uint8_t    high;\n\n            // set to zero\n            counter();\n\n            void increment();\n            void copy_to( std::uint8_t* target ) const;\n        };\n\n        /**\n         * @brief abstraction of the hardware that can be replaced during tests\n         *\n         * This abstracts the hardware operations (Radio, Timer)\n         */\n        class radio_hardware_without_crypto_support\n        {\n        public:\n            static int pdu_gap_required_by_encryption()\n            {\n                return 0;\n            }\n\n            static void init( void (*isr)( void* ), void* that );\n\n            /**\n             * @brief configure the radio to use the given channel\n             */\n            static void configure_radio_channel(\n                unsigned                                    channel );\n\n            /**\n             * @brief configure radio to transmit data and then start to reveive.\n             */\n            static void configure_transmit_train(\n                const bluetoe::link_layer::write_buffer&    transmit_data );\n\n            /**\n             * @brief configure the radio to transmit and then stop the radio.\n             */\n            static void configure_final_transmit(\n                const bluetoe::link_layer::write_buffer&    transmit_data );\n\n            /**\n             * @brief configure radio to receive data and then switch to\n             *        transmitting.\n             */\n            static void configure_receive_train(\n                const bluetoe::link_layer::read_buffer&     receive_buffer );\n\n            static void stop_radio();\n\n            /**\n             * @brief store the captured time anchor\n             */\n            static void store_timer_anchor( int offset_us );\n\n            /**\n             * @brief returns details to a received PDU\n             *\n             * Returns { true, X } if a PDU was received\n             * Returns { true, true, X } if that PDU is valid\n             * Returns { true, false, true } if that PDU has a valid CRC but maybe a MIC error\n             * Returns { true, false, false } if that PDU has an invalid CRC\n             */\n            static std::tuple< bool, bool, bool > received_pdu();\n\n            /**\n             * @brief elapsed time in µs since the last anchor\n             *\n             * @sa store_timer_anchor\n             */\n            static std::uint32_t now();\n\n            /**\n             * @brief try to stop the connection event and return the time from the\n             *        anchor.\n             */\n            static std::pair< bool, link_layer::delta_time > can_stop_connection_event_timer( std::uint32_t safety_margin_us );\n\n            static void setup_identity_resolving(\n                const std::uint8_t* )\n            {\n            }\n\n            static bool resolving_address_invalid()\n            {\n                return false;\n            }\n\n            static void set_phy(\n                bluetoe::link_layer::phy_ll_encoding::phy_ll_encoding_t receiving_encoding,\n                bluetoe::link_layer::phy_ll_encoding::phy_ll_encoding_t transmiting_c_encoding );\n\n            /**\n             * @brief triggers the radio.start task at when, disables the radio timeout_us later\n             *\n             * @return true, if the high frequency clock isn't used anymore\n             */\n            static bool schedule_advertisment_event_timer(\n                bluetoe::link_layer::delta_time when,\n                std::uint32_t                   timeout_us,\n                std::uint32_t                   start_hfxo_offset );\n\n            static void schedule_connection_event_timer(\n                std::uint32_t                   begin_us,\n                std::uint32_t                   end_us,\n                std::uint32_t                   start_hfxo_offset );\n\n            static bool schedule_user_timer(\n                void (*isr)( void* ),\n                std::uint32_t                   time_us,\n                std::uint32_t                   max_cb_runtimer_ms );\n\n            static bool stop_user_timer();\n            /**\n             * @brief stop the timer from disabling the RADIO\n             */\n            static void stop_timeout_timer();\n\n            static std::uint32_t static_random_address_seed();\n\n            static void set_access_address_and_crc_init( std::uint32_t access_address, std::uint32_t crc_init );\n\n            static void debug_toggle();\n\n            /**\n             * @brief returns true, if the anchor was move since the last call to this function\n             *        and resets the flag.\n             */\n            static bool user_timer_anchor_moved();\n\n            class lock_guard\n            {\n            public:\n                // see https://devzone.nordicsemi.com/question/47493/disable-interrupts-and-enable-interrupts-if-they-where-enabled/\n                lock_guard()\n                    : context_( __get_PRIMASK() )\n                {\n                    __disable_irq();\n                }\n\n                ~lock_guard()\n                {\n                    __set_PRIMASK( context_ );\n                }\n\n                lock_guard( const lock_guard& ) = delete;\n                lock_guard& operator=( const lock_guard& ) = delete;\n            private:\n                const std::uint32_t context_;\n            };\n\n\n        protected:\n            static bool          receive_2mbit_;\n            static bool          transmit_2mbit_;\n\n        private:\n\n            // as the end of the PDU is captured and the start of the connection event\n            // then calculated based on the PDU size, HF frequency domain anchor can be negativ\n            volatile static int           hf_connection_event_anchor_;\n            volatile static std::uint32_t lf_connection_event_anchor_;\n\n            // if between setting up a user timer and calling the corresponding callback,\n            // the anchor moved, inform the callback, so that the callback can schedule\n            // the next call to the new anchor\n            volatile static bool user_timer_anchor_moved_;\n        };\n\n        /**\n         * @brief abstraction of the hardware that can be replaced during tests\n         *\n         * This abstract extends the radio_hardware_without_crypto_support abstraction,\n         * by adding function, necessary for encrypting the link.\n         */\n        class radio_hardware_with_crypto_support : public radio_hardware_without_crypto_support\n        {\n        public:\n            static int pdu_gap_required_by_encryption()\n            {\n                return 1;\n            }\n\n            using radio_hardware_without_crypto_support::init;\n            static void init( std::uint8_t* encrypted_area, void (*isr)( void* ), void* that );\n\n            static void configure_transmit_train(\n                const bluetoe::link_layer::write_buffer&    transmit_data );\n\n            static void configure_final_transmit(\n                const bluetoe::link_layer::write_buffer&    transmit_data );\n\n            static void configure_receive_train(\n                const bluetoe::link_layer::read_buffer&     receive_buffer );\n\n            static void store_timer_anchor( int offset_us );\n\n            static std::tuple< bool, bool, bool > received_pdu();\n\n            static void configure_encryption( bool receive, bool transmit );\n\n            static std::pair< std::uint64_t, std::uint32_t > setup_encryption( bluetoe::details::uint128_t key, std::uint64_t skdm, std::uint32_t ivm );\n\n            static void increment_receive_packet_counter()\n            {\n                receive_counter_.increment();\n            }\n\n            static void increment_transmit_packet_counter()\n            {\n                transmit_counter_.increment();\n            }\n\n            /*\n             * @brief set the advertising address\n             */\n            static void setup_identity_resolving_address(\n                const std::uint8_t* address );\n\n            /*\n             * @brief enable identity resolving and the set the corresponding key\n             */\n            static void set_identity_resolving_key(\n                const details::identity_resolving_key_t& irk );\n\n            /*\n             * @brief returns true, if a request steams from an invalid address\n             */\n            static bool resolving_address_invalid();\n\n        private:\n            static volatile bool    receive_encrypted_;\n            static volatile bool    transmit_encrypted_;\n            static std::uint8_t*    encrypted_area_;\n            static counter          receive_counter_;\n            static counter          transmit_counter_;\n            static bool             identity_resolving_enabled_;\n        };\n\n        template < typename ... Options >\n        struct radio_options\n        {\n            using result = typename bluetoe::details::find_all_by_meta_type<\n                bluetoe::nrf::nrf_details::radio_option_meta_type,\n                Options...\n            >::type;\n        };\n\n        template < typename ... Options >\n        struct link_layer_options\n        {\n            using result = typename bluetoe::details::find_all_by_not_meta_type<\n                bluetoe::details::binding_option_meta_type,\n                Options...\n            >::type;\n        };\n\n        template < class CallBacks, class Hardware, class Buffer, typename ... RadioOptions >\n        class nrf52_radio_base : public Buffer\n        {\n        public:\n            nrf52_radio_base()\n            {\n               low_frequency_clock_t::start_clocks();\n                Hardware::init( []( void* that ){\n                    static_cast< nrf52_radio_base* >( that )->radio_interrupt_handler();\n                }, this);\n            }\n\n            nrf52_radio_base( std::uint8_t* receive_buffer )\n            {\n               low_frequency_clock_t::start_clocks();\n                Hardware::init( receive_buffer, []( void* that ){\n                    static_cast< nrf52_radio_base* >( that )->radio_interrupt_handler();\n                }, this);\n            }\n\n            void schedule_advertisment(\n                unsigned                                    channel,\n                const bluetoe::link_layer::write_buffer&    advertising_data,\n                const bluetoe::link_layer::write_buffer&    response_data,\n                bluetoe::link_layer::delta_time             when,\n                const bluetoe::link_layer::read_buffer&     receive )\n            {\n                assert( !adv_received_ );\n                assert( !adv_timeout_ );\n                assert( state_ == state::idle );\n                assert( receive.buffer && receive.size >= 2u );\n\n                bluetoe::link_layer::write_buffer advertising = advertising_data;\n                advertising.size = std::min< std::uint8_t >( advertising.size, maximum_advertising_pdu_size );\n\n                response_data_       = response_data;\n                receive_buffer_      = receive;\n                receive_buffer_.size = std::min< std::size_t >( receive.size, maximum_advertising_pdu_size );\n\n                Hardware::configure_radio_channel( channel );\n                Hardware::configure_transmit_train( advertising );\n\n                Hardware::setup_identity_resolving( receive_buffer_.buffer + connect_addr_offset );\n\n                // Advertising size + LL header + preable + access address + CRC\n                const std::uint32_t read_timeout = ( advertising.size + 2 + 1 + 4 + 3 ) * 8 + adv_reponse_timeout_us;\n\n                state_ = state::adv_transmitting;\n\n                if ( Hardware::schedule_advertisment_event_timer( when, read_timeout, hfxo_startup_value ) )\n                    low_frequency_clock_t::stop_high_frequency_crystal_oscilator();\n            }\n\n            link_layer::delta_time schedule_connection_event(\n                unsigned                                    channel,\n                bluetoe::link_layer::delta_time             start_receive,\n                bluetoe::link_layer::delta_time             end_receive,\n                bluetoe::link_layer::delta_time             connection_interval )\n            {\n                assert( !end_evt_ );\n                assert( state_ == state::idle );\n                assert( start_receive < end_receive );\n\n                // in case of a call to nrf_flash_memory_access_end, evt_timeout_ will be set\n                // and needs to be consumed by the timeout handler\n                if ( evt_timeout_ )\n                    return connection_interval;\n\n                // Stop all interrupts so that the calculation, that enough CPU time is available to setup everything, will not\n                // be disturbed by any interrupt.\n                lock_guard lock;\n\n                const std::uint32_t start_event = start_receive.usec();\n                // TODO: 500: must depend on receive size. This probably would depend on the maximum\n                // LL PDU size that would be expected.\n                const std::uint32_t end_event   = end_receive.usec() + 500;\n\n                const auto now = Hardware::now();\n                if ( now + start_event_safety_margin_us > start_event )\n                {\n                    evt_timeout_ = true;\n                    return connection_interval;\n                }\n\n                receive_buffer_ = receive_buffer();\n                state_          = state::evt_wait_connect;\n\n                Hardware::configure_radio_channel( channel );\n                Hardware::configure_receive_train( receive_buffer_ );\n\n                Hardware::schedule_connection_event_timer( start_event, end_event, hfxo_startup_value );\n                low_frequency_clock_t::stop_high_frequency_crystal_oscilator();\n\n                return link_layer::delta_time( connection_interval.usec() - now );\n            }\n\n            std::pair< bool, link_layer::delta_time > disarm_connection_event()\n            {\n                lock_guard lock;\n\n                const auto result = Hardware::can_stop_connection_event_timer( start_event_safety_margin_us );\n\n                if ( result.first )\n                {\n                    Hardware::stop_radio();\n                    state_ = state::idle;\n                }\n\n                return result;\n            }\n\n            bool schedule_synchronized_user_timer(\n                    bluetoe::link_layer::delta_time timer,\n                    bluetoe::link_layer::delta_time max_cb_runtime )\n            {\n                return Hardware::schedule_user_timer( []( void* that ){\n                    const auto this_ = static_cast< nrf52_radio_base* >( that );\n                    const auto callbacks = static_cast< CallBacks* >( this_ );\n\n                    callbacks->user_timer( Hardware::user_timer_anchor_moved() );\n\n                }, timer.usec(), max_cb_runtime.usec() );\n            }\n\n            bool cancel_synchronized_user_timer()\n            {\n                return Hardware::stop_user_timer();\n            }\n\n            void set_access_address_and_crc_init( std::uint32_t access_address, std::uint32_t crc_init )\n            {\n                Hardware::set_access_address_and_crc_init( access_address, crc_init );\n            }\n\n            void run()\n            {\n                static constexpr bool single_wfi = bluetoe::details::has_option<\n                    nrf::leave_run_on_interrupt, RadioOptions... >::value;\n\n                if ( single_wfi )\n                {\n                    if ( !adv_received_ && !adv_timeout_ && !evt_timeout_ && !end_evt_ && wake_up_ == 0 )\n                        __WFI();\n                }\n                else\n                {\n                    while ( !adv_received_ && !adv_timeout_ && !evt_timeout_ && !end_evt_ && wake_up_ == 0 )\n                        __WFI();\n                }\n\n                // For every event, but the wakeup request, the radio should be in an idle state\n                // because it's up to the event handler to defined what should happen next\n                if ( adv_received_ )\n                {\n                    assert( state_ == state::idle );\n                    assert( reinterpret_cast< std::uint8_t* >( NRF_RADIO->PACKETPTR ) == receive_buffer_.buffer );\n\n                    receive_buffer_.size = std::min< std::size_t >(\n                        receive_buffer_.size,\n                        ( receive_buffer_.buffer[ 1 ] & 0x3f ) + 2 + Hardware::pdu_gap_required_by_encryption()\n                    );\n                    adv_received_ = false;\n\n                    static_cast< CallBacks* >( this )->adv_received( receive_buffer_ );\n                }\n\n                if ( adv_timeout_ )\n                {\n                    assert( state_ == state::idle );\n                    adv_timeout_ = false;\n                    static_cast< CallBacks* >( this )->adv_timeout();\n                }\n\n                if ( evt_timeout_ )\n                {\n                    assert( state_ == state::idle );\n                    evt_timeout_ = false;\n                    static_cast< CallBacks* >( this )->timeout();\n                }\n\n                if ( end_evt_ )\n                {\n                    assert( state_ == state::idle );\n                    end_evt_ = false;\n                    static_cast< CallBacks* >( this )->end_event( events_ );\n\n                    events_ = link_layer::connection_event_events();\n                }\n\n                if ( request_event_cancelation_ )\n                {\n                    request_event_cancelation_ = false;\n                    static_cast< CallBacks* >( this )->try_event_cancelation();\n                }\n\n                if ( wake_up_ )\n                {\n                    --wake_up_;\n                }\n            }\n\n            void wake_up()\n            {\n                ++wake_up_;\n            }\n\n            void request_event_cancelation()\n            {\n                request_event_cancelation_ = true;\n            }\n\n\n            std::uint32_t static_random_address_seed() const\n            {\n                return Hardware::static_random_address_seed();\n            }\n\n            void nrf_flash_memory_access_begin()\n            {\n                lock_guard lock;\n\n                Hardware::stop_radio();\n                low_frequency_clock_t::stop_high_frequency_crystal_oscilator();\n                state_ = state::idle;\n            }\n\n            void nrf_flash_memory_access_end()\n            {\n                // radio should still be in idle state, otherwise there was some interaction with the\n                // radio that was not expected by this function.\n                assert( state_ == state::idle );\n                // this kicks the CPU out of the loop in run() and requests the link layer to setup the next connection event\n                // unless, there is already a pending call to the end_event() handler.\n                evt_timeout_ = !end_evt_;\n            }\n\n            void radio_set_phy(\n                bluetoe::link_layer::phy_ll_encoding::phy_ll_encoding_t receiving_encoding,\n                bluetoe::link_layer::phy_ll_encoding::phy_ll_encoding_t transmiting_c_encoding )\n            {\n                Hardware::set_phy( receiving_encoding, transmiting_c_encoding );\n            }\n\n            using lock_guard = typename Hardware::lock_guard;\n\n            // no native white list implementation atm\n            static constexpr std::size_t radio_maximum_white_list_entries = 0;\n\n            /**\n             * @brief indicates support for 2Mbit\n             */\n            static constexpr bool hardware_supports_2mbit = true;\n\n            /**\n             * @brief indicates support for schedule_synchronized_user_timer()\n             */\n            static constexpr bool hardware_supports_synchronized_user_timer = true;\n\n            static constexpr unsigned connection_event_setup_time_us = nrf52_radio_base::start_event_safety_margin_us;\n\n        private:\n            using low_frequency_clock_t = typename bluetoe::details::find_by_meta_type<\n                nrf::nrf_details::sleep_clock_source_meta_type,\n                RadioOptions...,\n                bluetoe::nrf::calibrated_rc_sleep_clock >::type;\n\n            using hfxo_startup_time_t = typename bluetoe::details::find_by_meta_type<\n                nrf::nrf_details::hfxo_startup_time_meta_type,\n                RadioOptions...,\n                bluetoe::nrf::high_frequency_crystal_oscillator_startup_time_default >::type;\n\n            /*\n             * The startup time of the HFXO in LF clock periods\n             */\n            static constexpr std::uint32_t hfxo_startup_value =\n                ( hfxo_startup_time_t::value + 1000000 / nrf::lfxo_clk_freq ) * nrf::lfxo_clk_freq / 1000000;\n\n            /*\n             * The startup time rounded up to the next full period of the sleep clock\n             */\n            static constexpr std::uint32_t hfxo_startup_time = hfxo_startup_value * 1000000 / nrf::lfxo_clk_freq;\n\n            /*\n             * Margin required to safetely setup the connection event in µs.\n             */\n            static constexpr std::uint32_t start_event_safety_margin_us = setup_connection_event_limit_us + hfxo_startup_time;\n\n\n            link_layer::read_buffer receive_buffer()\n            {\n                link_layer::read_buffer result = this->allocate_receive_buffer();\n                if ( result.empty() )\n                    result = link_layer::read_buffer{ &empty_receive_[ 0 ], sizeof( empty_receive_ ) };\n\n                return result;\n            }\n\n            void radio_interrupt_handler()\n            {\n                if ( state_ == state::adv_transmitting )\n                {\n                    // The timeout timer was already set with the start of the advertising\n                    // Configure Radio to receive and then switch to transmitting\n                    Hardware::configure_receive_train( receive_buffer_ );\n                    state_ = state::adv_receiving;\n                }\n                else if ( state_ == state::adv_receiving )\n                {\n                    bool valid_anchor, valid_pdu, valid_crc;\n                    std::tie( valid_anchor, valid_pdu, valid_crc ) = Hardware::received_pdu();\n\n                    if ( valid_anchor && valid_pdu && valid_crc )\n                    {\n                        Hardware::stop_timeout_timer();\n\n                        if ( is_valid_scan_request() )\n                        {\n                            Hardware::configure_final_transmit( response_data_ );\n                            state_ = state::adv_transmitting_response;\n\n                            return;\n                        }\n\n                        adv_received_ = true;\n\n                        // In case of an connection request, the anchor is exactly the end\n                        // of the request\n                        Hardware::store_timer_anchor( 0 );\n                    }\n                    else\n                    {\n                        adv_timeout_ = true;\n                    }\n\n                    Hardware::stop_radio();\n\n                    state_       = state::idle;\n                }\n                else if ( state_ == state::adv_transmitting_response )\n                {\n                    Hardware::stop_radio();\n\n                    state_       = state::idle;\n                    adv_timeout_ = true;\n                }\n                else if ( state_ == state::evt_wait_connect )\n                {\n                    bool valid_anchor, valid_pdu, valid_crc;\n                    std::tie( valid_anchor, valid_pdu, valid_crc ) = Hardware::received_pdu();\n\n                    if ( valid_anchor && ( valid_pdu || valid_crc ) )\n                    {\n                        // switch to transmission\n                        const auto trans = ( receive_buffer_.buffer == &empty_receive_[ 0 ] || !valid_crc )\n                            ? this->next_transmit()\n                            : ( valid_pdu\n                                ? this->received( receive_buffer_ )\n                                : this->acknowledge( receive_buffer_ ) );\n\n                        // TODO: Hack to disable the more data flag, because this radio implementation is currently\n                        // not able to do this (but it should be possible with the given hardware).\n                        // Issue: #75 More Data not working\n                        const_cast< std::uint8_t* >( trans.buffer )[ 0 ] = trans.buffer[ 0 ] & ~more_data_flag;\n\n                        if ( trans.buffer[ 1 ] != 0 )\n                            events_.last_transmitted_not_empty = true;\n\n                        Hardware::configure_final_transmit( trans );\n                        state_   = state::evt_transmiting_closing;\n                    }\n                    else\n                    {\n                        Hardware::stop_radio();\n                        events_.error_occured = true;\n                        evt_timeout_  = true;\n                        state_        = state::idle;\n                    }\n                }\n                else if ( state_ == state::evt_transmiting_closing )\n                {\n                    // TODO: Couldn't we just capture the time at the start of the PDU?\n                    // the timer was captured with the end event; the anchor is the start of the receiving.\n                    // Additional to the ll PDU length there are 1 byte preamble, 4 byte access address, 2 byte LL header and 3 byte crc.\n                    // Issue: #76 Taking Anchor from End of PDU\n                    static constexpr std::size_t ll_pdu_overhead = 1 + 4 + 2 + 3;\n                    const int total_pdu_length = ( receive_buffer_.buffer[ 1 ] + ll_pdu_overhead ) * 8;\n\n                    // TODO: Anchor must also be taken, if PDU has a CRC error\n                    // Issue: #76 Taking Anchor from End of PDU\n                    Hardware::store_timer_anchor( -total_pdu_length );\n\n                    if ( receive_buffer_.buffer[ 1 ] != 0 )\n                        events_.last_received_not_empty = true;\n\n                    if ( receive_buffer_.buffer[ 0 ] & more_data_flag )\n                        events_.last_received_had_more_data = true;\n\n                    Hardware::stop_radio();\n                    state_   = state::idle;\n                    end_evt_ = true;\n                }\n                else\n                {\n                    assert(!\"Invalid state\");\n                }\n            }\n\n            bool is_valid_scan_request() const\n            {\n                static constexpr std::uint8_t scan_request_size     = 12;\n                static constexpr std::uint8_t scan_request_pdu_type = 0x03;\n                static constexpr std::uint8_t pdu_type_mask         = 0x0F;\n                static constexpr int          pdu_header_size       = 2;\n                static constexpr int          addr_size             = 6;\n                static constexpr std::uint8_t tx_add_mask           = 0x40;\n                static constexpr std::uint8_t rx_add_mask           = 0x80;\n\n                // the advertising type does not expect a scan request\n                if ( !response_data_.buffer )\n                    return false;\n\n                if ( Hardware::resolving_address_invalid() )\n                    return true;\n\n                if ( receive_buffer_.buffer[ 1 ] != scan_request_size )\n                    return false;\n\n                if ( ( receive_buffer_.buffer[ 0 ] & pdu_type_mask ) != scan_request_pdu_type )\n                    return false;\n\n                const int pdu_gap = Hardware::pdu_gap_required_by_encryption();\n\n                if ( !std::equal( &receive_buffer_.buffer[ pdu_header_size + addr_size + pdu_gap ], &receive_buffer_.buffer[ pdu_header_size + 2 * addr_size + pdu_gap ],\n                    &response_data_.buffer[ pdu_header_size + pdu_gap ] ) )\n                    return false;\n\n                // in the scan request, the randomness is stored in RxAdd, in the scan response, it's stored in\n                // TxAdd.\n                const bool scanner_addres_is_random = response_data_.buffer[ 0 ] & tx_add_mask;\n                if ( !static_cast< bool >( receive_buffer_.buffer[ 0 ] & rx_add_mask ) == scanner_addres_is_random )\n                    return false;\n\n                const link_layer::device_address scanner( &receive_buffer_.buffer[ pdu_header_size + pdu_gap ], scanner_addres_is_random );\n\n                return static_cast< const CallBacks* >( this )->is_scan_request_in_filter( scanner );\n            }\n\n            volatile bool adv_timeout_;\n            volatile bool adv_received_;\n            volatile bool evt_timeout_;\n            volatile bool end_evt_;\n            volatile bool request_event_cancelation_;\n            volatile int  wake_up_;\n\n            enum class state {\n                idle,\n                // timeout while receiving, stopping the radio, waiting for the radio to become disabled\n                adv_transmitting,\n                adv_receiving,\n                adv_transmitting_response,\n                adv_shutting_down_radio,\n                // connection event\n                evt_wait_connect,\n                evt_transmiting_closing,\n            };\n\n            volatile state                      state_;\n\n            link_layer::read_buffer             receive_buffer_;\n            link_layer::write_buffer            response_data_;\n            std::uint8_t                        empty_receive_[ 3 ];\n            link_layer::connection_event_events events_;\n        };\n\n        template <\n            std::size_t TransmitSize,\n            std::size_t ReceiveSize,\n            bool EnabledEncryption,\n            class CallBacks,\n            class Hardware,\n            typename ... RadioOptions\n        >\n        class nrf52_radio;\n\n        template <\n            std::size_t TransmitSize,\n            std::size_t ReceiveSize,\n            class CallBacks,\n            class Hardware,\n            typename ... RadioOptions\n        >\n        class nrf52_radio< TransmitSize, ReceiveSize, false, CallBacks, Hardware, RadioOptions... > :\n            public nrf52_radio_base< CallBacks, Hardware, bluetoe::link_layer::ll_data_pdu_buffer< TransmitSize, ReceiveSize, nrf52_radio< TransmitSize, ReceiveSize, false, CallBacks, Hardware, RadioOptions... > >,\n                                    RadioOptions... >\n        {\n        public:\n            static constexpr bool hardware_supports_encryption = false;\n\n            void increment_receive_packet_counter() {}\n            void increment_transmit_packet_counter() {}\n        };\n\n        template <\n            std::size_t TransmitSize,\n            std::size_t ReceiveSize,\n            class CallBacks,\n            class Hardware,\n            typename ... RadioOptions\n        >\n        class nrf52_radio< TransmitSize, ReceiveSize, true, CallBacks, Hardware, RadioOptions... > :\n            public nrf52_radio_base<\n                CallBacks,\n                Hardware,\n                bluetoe::link_layer::ll_data_pdu_buffer< TransmitSize, ReceiveSize,\n                    nrf52_radio< TransmitSize, ReceiveSize, true, CallBacks, Hardware, RadioOptions... > >,\n                    RadioOptions... >,\n            public security_tool_box\n        {\n        public:\n            static constexpr bool hardware_supports_lesc_pairing    = true;\n            static constexpr bool hardware_supports_legacy_pairing  = true;\n            static constexpr bool hardware_supports_encryption      = hardware_supports_lesc_pairing || hardware_supports_legacy_pairing;\n\n            using radio_base_t = nrf52_radio_base<\n                CallBacks,\n                Hardware,\n                bluetoe::link_layer::ll_data_pdu_buffer< TransmitSize, ReceiveSize,\n                    nrf52_radio< TransmitSize, ReceiveSize, true, CallBacks, Hardware, RadioOptions... > >,\n                    RadioOptions...  >;\n\n            nrf52_radio() : radio_base_t( encrypted_message_.data )\n            {\n            }\n\n            std::pair< std::uint64_t, std::uint32_t > setup_encryption( bluetoe::details::uint128_t key, std::uint64_t skdm, std::uint32_t ivm )\n            {\n                return Hardware::setup_encryption( key, skdm, ivm );\n            }\n\n            /**\n             * @brief start the encryption of received PDUs with the next connection event.\n             */\n            void start_receive_encrypted()\n            {\n                Hardware::configure_encryption( true, false );\n            }\n\n            /**\n             * @brief start to encrypt transmitted PDUs with the next connection event.\n             */\n            void start_transmit_encrypted()\n            {\n                Hardware::configure_encryption( true, true );\n            }\n\n            /**\n             * @brief stop receiving encrypted with the next connection event.\n             */\n            void stop_receive_encrypted()\n            {\n                Hardware::configure_encryption( false, true );\n            }\n\n            /**\n             * @brief stop transmitting encrypted with the next connection event.\n             */\n            void stop_transmit_encrypted()\n            {\n                Hardware::configure_encryption( false, false );\n            }\n\n            void increment_receive_packet_counter()\n            {\n                Hardware::increment_receive_packet_counter();\n            }\n\n            void increment_transmit_packet_counter()\n            {\n                Hardware::increment_transmit_packet_counter();\n            }\n\n            /**\n             * @brief sets an IRK filter for incomming scan requests and connection requests\n             *\n             * Has to be called when the radio is not in a connection or after disconnected.\n             * Experimental!\n             */\n            void set_identity_resolving_key( const details::identity_resolving_key_t& irk )\n            {\n                Hardware::set_identity_resolving_key( irk );\n            }\n\n        private:\n            // TODO should be calculated with more accuracy base on the configuration of:\n            // - l2cap MAX MTU\n            // - implementation of Data Length Update procedure\n            struct alignas( 4 ) encrypted_message_t {\n                std::uint8_t data[ 260 ];\n            } encrypted_message_;\n        };\n\n        template < typename Server, bool EnabledEncryption, typename RadioOptions, typename LinkLayerOptions >\n        struct link_layer_factory;\n\n        template < typename Server, bool EnabledEncryption, typename ... RadioOptions, typename ... LinkLayerOptions >\n        struct link_layer_factory< Server, EnabledEncryption, std::tuple< RadioOptions... >, std::tuple< LinkLayerOptions... > >\n        {\n            using radio_hardware_t = typename details::select_type<\n                EnabledEncryption,\n                radio_hardware_with_crypto_support,\n                radio_hardware_without_crypto_support >::type;\n\n            template <\n                std::size_t TransmitSize,\n                std::size_t ReceiveSize,\n                class CallBacks\n            >\n            using radio_t = nrf52_radio< TransmitSize, ReceiveSize, EnabledEncryption, CallBacks, radio_hardware_t, RadioOptions... >;\n\n            using link_layer = bluetoe::link_layer::link_layer< Server, radio_t, LinkLayerOptions... >;\n        };\n    }\n\n    namespace link_layer {\n\n        /** @cond HIDDEN_SYMBOLS */\n        /*\n         * specialize pdu_layout_by_radio<> for the radio that supports encryption to change the PDU layout\n         * to have that extra byte between header and body\n         */\n        template <\n            std::size_t TransmitSize,\n            std::size_t ReceiveSize,\n            class CallBacks,\n            class Hardware,\n            typename ... RadioOptions\n        >\n        struct pdu_layout_by_radio<\n            nrf52_details::nrf52_radio< TransmitSize, ReceiveSize, true, CallBacks, Hardware, RadioOptions... > >\n        {\n            /**\n             * When using encryption, the Radio and the AES CCM peripheral expect an \"RFU\" byte between LL header and\n             * payload.\n             */\n            using pdu_layout = bluetoe::nrf_details::encrypted_pdu_layout;\n        };\n        /** @endcond */\n    }\n\n    /**\n     * @brief binding for nRF52 microcontrollers\n     *\n     * Options that are ment to configure the nRF52 bindings are:\n     * bluetoe::nrf::sleep_clock_crystal_oscillator\n     * bluetoe::nrf::calibrated_sleep_clock\n     * bluetoe::nrf::synthesized_sleep_clock\n     * bluetoe::nrf::leave_run_on_interrupt\n     */\n    template < class Server, typename ... Options >\n    using nrf52 = typename nrf52_details::link_layer_factory<\n        Server,\n        details::requires_encryption_support_t< Server >::value,\n        typename nrf52_details::radio_options< Options... >::result,\n        typename nrf52_details::link_layer_options< Options... >::result\n    >::link_layer;\n}\n\n#endif\n"
  },
  {
    "path": "bluetoe/bindings/nordic/nrf52/include/bluetoe/security_tool_box.hpp",
    "content": "#ifndef BLUETOE_BINDING_NORDIC_NRF52_SECURITY_TOOL_BOX_HPP\n#define BLUETOE_BINDING_NORDIC_NRF52_SECURITY_TOOL_BOX_HPP\n\n#include <bluetoe/security_manager.hpp>\n\n#include <tuple>\n#include <algorithm>\n\nnamespace bluetoe\n{\n    namespace nrf52_details\n    {\n        std::uint32_t random_number32();\n        std::uint64_t random_number64();\n        bluetoe::details::uint128_t aes_le( const bluetoe::details::uint128_t& key, const bluetoe::details::uint128_t& data );\n\n        /**\n         * @brief set of security tool box functions, both for legacy pairing and LESC pairing\n         *\n         * It's expected that only the required set of functions are requested by the linker.\n         */\n        class security_tool_box\n        {\n        public:\n            /**\n             * security tool box required by legacy pairing\n             */\n            bluetoe::details::uint128_t create_srand();\n\n            bluetoe::details::longterm_key_t create_long_term_key();\n\n            bluetoe::details::uint128_t c1(\n                const bluetoe::details::uint128_t& temp_key,\n                const bluetoe::details::uint128_t& rand,\n                const bluetoe::details::uint128_t& p1,\n                const bluetoe::details::uint128_t& p2 ) const;\n\n            bluetoe::details::uint128_t s1(\n                const bluetoe::details::uint128_t& temp_key,\n                const bluetoe::details::uint128_t& srand,\n                const bluetoe::details::uint128_t& mrand );\n\n            /**\n             * security tool box required by LESC pairing\n             */\n            bool is_valid_public_key( const std::uint8_t* public_key ) const;\n\n            /**\n             * @brief generate public private key pair for DH\n             */\n            std::pair< bluetoe::details::ecdh_public_key_t, bluetoe::details::ecdh_private_key_t > generate_keys();\n\n            /**\n             * @brief random nonce required for LESC pairing\n             */\n            bluetoe::details::uint128_t select_random_nonce();\n\n            /**\n             * @brief p256() security toolbox function, as specified in the core spec\n             */\n            bluetoe::details::ecdh_shared_secret_t p256( const std::uint8_t* private_key, const std::uint8_t* public_key );\n\n            /**\n             * @brief f4() security toolbox function, as specified in the core spec\n             */\n            bluetoe::details::uint128_t f4( const std::uint8_t* u, const std::uint8_t* v, const std::array< std::uint8_t, 16 >& k, std::uint8_t z );\n\n            /**\n             * @brief f5() security toolbox function, as specified in the core spec\n             */\n            std::pair< bluetoe::details::uint128_t, bluetoe::details::uint128_t > f5(\n                const bluetoe::details::ecdh_shared_secret_t dh_key,\n                const bluetoe::details::uint128_t& nonce_central,\n                const bluetoe::details::uint128_t& nonce_periperal,\n                const bluetoe::link_layer::device_address& addr_controller,\n                const bluetoe::link_layer::device_address& addr_peripheral );\n\n            /**\n             * @brief f6() security toolbox function, as specified in the core spec\n             */\n            bluetoe::details::uint128_t f6(\n                const bluetoe::details::uint128_t& key,\n                const bluetoe::details::uint128_t& n1,\n                const bluetoe::details::uint128_t& n2,\n                const bluetoe::details::uint128_t& r,\n                const bluetoe::details::io_capabilities_t& io_caps,\n                const bluetoe::link_layer::device_address& addr_controller,\n                const bluetoe::link_layer::device_address& addr_peripheral );\n\n            /**\n             * @brief g2() security toolbox function, as specified in the core spec\n             */\n            std::uint32_t g2(\n                const std::uint8_t*                 u,\n                const std::uint8_t*                 v,\n                const bluetoe::details::uint128_t&  x,\n                const bluetoe::details::uint128_t&  y );\n\n            /**\n             * Functions required by IO capabilties\n             */\n            bluetoe::details::uint128_t create_passkey();\n        };\n\n    }\n}\n\n#endif\n"
  },
  {
    "path": "bluetoe/bindings/nordic/nrf52/nrf52.cpp",
    "content": "#include <bluetoe/nrf52.hpp>\n\n#include <bluetoe/bits.hpp>\n\n#include <cstring>\n#include <algorithm>\n\nnamespace bluetoe\n{\nusing namespace bluetoe::nrf;\n\nnamespace nrf52_details\n{\n    static constexpr std::size_t        radio_address_ccm_crypt         = 25;\n    static constexpr std::size_t        radio_end_capture2_ppi_channel  = 27;\n    static constexpr std::size_t        compare0_txen_ppi_channel       = 20;\n    static constexpr std::size_t        compare0_rxen_ppi_channel       = 21;\n    static constexpr std::size_t        compare1_disable_ppi_channel    = 22;\n    static constexpr std::size_t        radio_bcmatch_aar_start_channel = 23;\n    static constexpr std::size_t        rtc0_start_tim_ppi_channel      = 31;\n\n    static constexpr std::uint32_t      all_preprogramed_ppi_channels_mask =\n        ( 1 << radio_address_ccm_crypt )\n      | ( 1 << radio_end_capture2_ppi_channel )\n      | ( 1 << compare0_txen_ppi_channel )\n      | ( 1 << compare0_rxen_ppi_channel )\n      | ( 1 << compare1_disable_ppi_channel )\n      | ( 1 << radio_bcmatch_aar_start_channel )\n      | ( 1 << rtc0_start_tim_ppi_channel );\n\n    static constexpr std::uint32_t      transmit_ppi_channels =\n        ( 1 << compare0_txen_ppi_channel )\n      | ( 1 << compare1_disable_ppi_channel );\n\n    static constexpr std::uint32_t      receive_ppi_channels =\n        ( 1 << compare0_rxen_ppi_channel )\n      | ( 1 << compare1_disable_ppi_channel );\n\n    // allocation of PPI channels\n    enum ppi_channels_used {\n        // Channels only used, if BLUETOE_NRF52_RADIO_DEBUG is set\n        trace_debug_ppi_channel_1        = 9,\n        trace_debug_ppi_channel_2        = 10,\n        trace_clock_hfxo_ppi_channel     = 11,\n        trace_radio_address_ppi_channel  = 12,\n        trace_radio_end_ppi_channel      = 13,\n        trace_ccm_endcrypt_ppi_channel   = 14,\n        trace_ccm_endksgen_ppi_channel   = 15,\n        trace_radio_ready_ppi_channel    = 16,\n        trace_radio_disabled_ppi_channel = 17,\n        // Channels always used\n        // !!! If this allocation changes, make sure, the documentation in nrf52.hpp is updated\n        rtc_start_cb_timer_ppi_channel   = 18,\n        rtc_start_hfxo_ppi_channel       = 19,\n    };\n\n    static constexpr std::uint32_t      all_radio_ppi_channels_mask =\n        all_preprogramed_ppi_channels_mask\n      | ( 1 << rtc_start_hfxo_ppi_channel );\n\n    // Allocation of the compare/capture registers of the RTC\n    enum rtc_capture_registers {\n        rtc_cc_start_timer = 0,\n        rtc_cc_start_hfxo  = 1,\n        rtc_cc_start_cb_timer = 2,\n    };\n\n    // Allocation of the compare/capture registers of TIMER0\n    enum timer_capture_registers {\n        tim_cc_start_radio    = 0,\n        tim_cc_timeout        = 1,\n        tim_cc_capture_anchor = 2,\n        tim_cc_capture_now    = 3\n    };\n\n    // Allocation of the compare/capture registers of TIMER1\n    enum cb_timer_capture_registers {\n        cb_tim_cc_start_exec_cb = 0,\n        cb_tim_cc_assert_end_cb = 1,\n    };\n\n    static void assign_channel(\n        ppi_channels_used channel,\n        volatile std::uint32_t& event,\n        volatile std::uint32_t& task )\n    {\n       nrf_ppi->CH[ channel ].EEP = reinterpret_cast< std::uint32_t >( &event );\n       nrf_ppi->CH[ channel ].TEP = reinterpret_cast< std::uint32_t >( &task );\n    }\n\n    static constexpr std::uint32_t timer_prescale_for_1us_resolution = 4;\n\n#   if defined BLUETOE_NRF52_RADIO_DEBUG\n        static constexpr int debug_pin_end_crypt     = 11;\n        static constexpr int debug_pin_ready_disable = 12;\n        static constexpr int debug_pin_address_end   = 13;\n        static constexpr int debug_pin_keystream     = 14;\n        static constexpr int debug_pin_debug         = 15;\n        static constexpr int debug_pin_isr           = 16;\n        static constexpr int debug_pin_hfxo          = 17;\n\n        void init_debug()\n        {\n            for ( auto pin : { debug_pin_end_crypt, debug_pin_ready_disable,\n                                debug_pin_address_end, debug_pin_keystream, debug_pin_debug,\n                                debug_pin_isr, debug_pin_hfxo } )\n            {\n                NRF_GPIO->PIN_CNF[ pin ] =\n                    ( GPIO_PIN_CNF_DRIVE_S0H1 << GPIO_PIN_CNF_DRIVE_Pos ) |\n                    ( GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos );\n            }\n\n            NRF_GPIOTE->CONFIG[ 0 ] =\n                ( GPIOTE_CONFIG_MODE_Task << GPIOTE_CONFIG_MODE_Pos ) |\n                ( debug_pin_address_end << GPIOTE_CONFIG_PSEL_Pos ) |\n                ( GPIOTE_CONFIG_POLARITY_Toggle << GPIOTE_CONFIG_POLARITY_Pos ) |\n                ( GPIOTE_CONFIG_OUTINIT_Low << GPIOTE_CONFIG_OUTINIT_Pos );\n\n            NRF_GPIOTE->CONFIG[ 1 ] =\n                ( GPIOTE_CONFIG_MODE_Task << GPIOTE_CONFIG_MODE_Pos ) |\n                ( debug_pin_keystream << GPIOTE_CONFIG_PSEL_Pos ) |\n                ( GPIOTE_CONFIG_POLARITY_Toggle << GPIOTE_CONFIG_POLARITY_Pos ) |\n                ( GPIOTE_CONFIG_OUTINIT_Low << GPIOTE_CONFIG_OUTINIT_Pos );\n\n            NRF_GPIOTE->CONFIG[ 2 ] =\n                ( GPIOTE_CONFIG_MODE_Task << GPIOTE_CONFIG_MODE_Pos ) |\n                ( debug_pin_ready_disable << GPIOTE_CONFIG_PSEL_Pos ) |\n                ( GPIOTE_CONFIG_POLARITY_Toggle << GPIOTE_CONFIG_POLARITY_Pos ) |\n                ( GPIOTE_CONFIG_OUTINIT_Low << GPIOTE_CONFIG_OUTINIT_Pos );\n\n            NRF_GPIOTE->CONFIG[ 3 ] =\n                ( GPIOTE_CONFIG_MODE_Task << GPIOTE_CONFIG_MODE_Pos ) |\n                ( debug_pin_end_crypt << GPIOTE_CONFIG_PSEL_Pos ) |\n                ( GPIOTE_CONFIG_POLARITY_Toggle << GPIOTE_CONFIG_POLARITY_Pos ) |\n                ( GPIOTE_CONFIG_OUTINIT_Low << GPIOTE_CONFIG_OUTINIT_Pos );\n\n            NRF_GPIOTE->CONFIG[ 4 ] =\n                ( GPIOTE_CONFIG_MODE_Task << GPIOTE_CONFIG_MODE_Pos ) |\n                ( debug_pin_hfxo << GPIOTE_CONFIG_PSEL_Pos ) |\n                ( GPIOTE_CONFIG_POLARITY_Toggle << GPIOTE_CONFIG_POLARITY_Pos ) |\n                ( GPIOTE_CONFIG_OUTINIT_Low << GPIOTE_CONFIG_OUTINIT_Pos );\n\n            NRF_GPIOTE->CONFIG[ 5 ] =\n                ( GPIOTE_CONFIG_MODE_Task << GPIOTE_CONFIG_MODE_Pos ) |\n                ( debug_pin_debug << GPIOTE_CONFIG_PSEL_Pos ) |\n                ( GPIOTE_CONFIG_POLARITY_Toggle << GPIOTE_CONFIG_POLARITY_Pos ) |\n                ( GPIOTE_CONFIG_OUTINIT_Low << GPIOTE_CONFIG_OUTINIT_Pos );\n\n            assign_channel( trace_clock_hfxo_ppi_channel, nrf_clock->EVENTS_HFCLKSTARTED, NRF_GPIOTE->TASKS_SET[ 4 ] );\n            assign_channel( trace_radio_address_ppi_channel, NRF_RADIO->EVENTS_ADDRESS, NRF_GPIOTE->TASKS_SET[ 0 ] );\n            assign_channel( trace_radio_end_ppi_channel, NRF_RADIO->EVENTS_END, NRF_GPIOTE->TASKS_CLR[ 0 ] );\n            assign_channel( trace_ccm_endcrypt_ppi_channel, NRF_CCM->EVENTS_ENDCRYPT, NRF_GPIOTE->TASKS_OUT[ 3 ] );\n            assign_channel( trace_ccm_endksgen_ppi_channel, NRF_CCM->EVENTS_ENDKSGEN, NRF_GPIOTE->TASKS_CLR[ 1 ] );\n            assign_channel( trace_radio_ready_ppi_channel, NRF_RADIO->EVENTS_READY, NRF_GPIOTE->TASKS_OUT[ 2 ] );\n            assign_channel( trace_radio_disabled_ppi_channel, NRF_RADIO->EVENTS_DISABLED, NRF_GPIOTE->TASKS_OUT[ 2 ] );\n            assign_channel( trace_debug_ppi_channel_1, nrf_timer->EVENTS_COMPARE[ tim_cc_timeout ], NRF_GPIOTE->TASKS_OUT[ 1 ] );\n\n            NRF_PPI->CHENSET =\n                ( 1 << trace_debug_ppi_channel_1 )\n              | ( 1 << trace_debug_ppi_channel_2 )\n              | ( 1 << trace_clock_hfxo_ppi_channel )\n              | ( 1 << trace_radio_address_ppi_channel )\n              | ( 1 << trace_radio_end_ppi_channel )\n              | ( 1 << trace_ccm_endcrypt_ppi_channel )\n              | ( 1 << trace_ccm_endksgen_ppi_channel )\n              | ( 1 << trace_radio_ready_ppi_channel )\n              | ( 1 << trace_radio_disabled_ppi_channel );\n        }\n\n        void toggle_debug_pin()\n        {\n            NRF_GPIOTE->TASKS_OUT[ 5 ] = 1;\n            NRF_GPIOTE->TASKS_OUT[ 5 ] = 1;\n        }\n\n        void set_isr_pin()\n        {\n            NRF_GPIO->OUTSET = ( 1 << debug_pin_isr );\n        }\n\n        void reset_isr_pin()\n        {\n            NRF_GPIO->OUTCLR = ( 1 << debug_pin_isr );\n        }\n\n        void gpio_debug_hfxo_stopped()\n        {\n            NRF_GPIOTE->TASKS_CLR[ 4 ] = 1;\n        }\n\n        struct record_long_distance_timer_params_t {\n            std::uint32_t hf_anchor;\n            std::uint32_t lf_anchor;\n            std::uint32_t us_radio_start_time;\n            std::uint32_t us_radio_startup_delay;\n            std::uint32_t us_radio_timeout;\n            std::uint32_t timer;\n            std::uint32_t clock;\n            std::uint32_t rtc_cc0;\n            std::uint32_t rtc_cc1;\n            std::uint32_t timer_cc0;\n            std::uint32_t timer_cc1;\n        };\n\n        static constexpr std::size_t record_long_distance_timer_size = 16;\n        record_long_distance_timer_params_t record_long_distance_timer_[ record_long_distance_timer_size ] = { { 0 } };\n        int record_long_distance_timer_ptr_ = 0;\n\n        void record_long_distance_timer(\n            const std::uint32_t hf_anchor,\n            const std::uint32_t lf_anchor,\n            const std::uint32_t us_radio_start_time,\n            const std::uint32_t us_radio_startup_delay,\n            const std::uint32_t us_radio_timeout )\n        {\n            nrf_timer->TASKS_CAPTURE[ tim_cc_capture_now ] = 1;\n            const std::uint32_t now = nrf_timer->CC[ tim_cc_capture_now ];\n\n            record_long_distance_timer_[ record_long_distance_timer_ptr_ ] = record_long_distance_timer_params_t{\n                .hf_anchor              = hf_anchor,\n                .lf_anchor              = lf_anchor,\n                .us_radio_start_time    = us_radio_start_time,\n                .us_radio_startup_delay = us_radio_startup_delay,\n                .us_radio_timeout       = us_radio_timeout,\n                .timer                  = now,\n                .clock                  = nrf_rtc->COUNTER,\n                .rtc_cc0                = nrf_rtc->CC[ rtc_cc_start_timer ],\n                .rtc_cc1                = nrf_rtc->CC[ rtc_cc_start_hfxo ],\n                .timer_cc0              = nrf_timer->CC[ tim_cc_start_radio ],\n                .timer_cc1              = nrf_timer->CC[ tim_cc_timeout ]\n            };\n\n            record_long_distance_timer_ptr_ = ( record_long_distance_timer_ptr_ + 1 ) % record_long_distance_timer_size;\n        }\n#   else\n        void init_debug() {}\n\n        void toggle_debug_pin() {}\n        void set_isr_pin() {}\n        void reset_isr_pin() {}\n        void gpio_debug_hfxo_stopped() {}\n        void record_long_distance_timer(\n            const std::uint32_t,\n            const std::uint32_t,\n            const std::uint32_t,\n            const std::uint32_t,\n            const std::uint32_t ) {}\n#   endif\n\n    /*\n     * Frequency correction if NRF_FICR_Type has an OVERRIDEEN field\n     */\n    template < typename F, typename R >\n    static auto override_correction(F* ficr, R* radio) -> decltype(F::OVERRIDEEN)\n    {\n#       ifndef FICR_OVERRIDEEN_BLE_1MBIT_Msk\n#           define FICR_OVERRIDEEN_BLE_1MBIT_Msk 1\n#       endif\n#       ifndef FICR_OVERRIDEEN_BLE_1MBIT_Override\n#           define FICR_OVERRIDEEN_BLE_1MBIT_Override 1\n#       endif\n#       ifndef FICR_OVERRIDEEN_BLE_1MBIT_Pos\n#           define FICR_OVERRIDEEN_BLE_1MBIT_Pos 1\n#       endif\n\n        if ( ( ficr->OVERRIDEEN & FICR_OVERRIDEEN_BLE_1MBIT_Msk ) == (FICR_OVERRIDEEN_BLE_1MBIT_Override << FICR_OVERRIDEEN_BLE_1MBIT_Pos) )\n        {\n            radio->OVERRIDE0 = ficr->BLE_1MBIT[0];\n            radio->OVERRIDE1 = ficr->BLE_1MBIT[1];\n            radio->OVERRIDE2 = ficr->BLE_1MBIT[2];\n            radio->OVERRIDE3 = ficr->BLE_1MBIT[3];\n            radio->OVERRIDE4 = ficr->BLE_1MBIT[4] | 0x80000000;\n        }\n\n        return ficr->OVERRIDEEN;\n    }\n\n    template < typename F >\n    static void override_correction(...)\n    {\n    }\n\n    static void init_radio( bool encryption_possible )\n    {\n        // TODO Use MODECNF0.RU to speedup rampup?\n        override_correction< NRF_FICR_Type >( NRF_FICR, nrf_radio );\n\n        nrf_radio->MODE  = RADIO_MODE_MODE_Ble_1Mbit << RADIO_MODE_MODE_Pos;\n        nrf_radio->MODECNF0    =\n            ( RADIO_MODECNF0_DTX_Center << RADIO_MODECNF0_DTX_Pos );\n\n        nrf_radio->PCNF0 =\n            ( 1 << RADIO_PCNF0_S0LEN_Pos ) |\n            ( 8 << RADIO_PCNF0_LFLEN_Pos ) |\n            ( 0 << RADIO_PCNF0_S1LEN_Pos ) |\n            ( encryption_possible\n                ? ( RADIO_PCNF0_S1INCL_Include << RADIO_PCNF0_S1INCL_Pos )\n                : ( RADIO_PCNF0_S1INCL_Automatic << RADIO_PCNF0_S1INCL_Pos ) );\n\n        nrf_radio->PCNF1 =\n            ( RADIO_PCNF1_WHITEEN_Enabled << RADIO_PCNF1_WHITEEN_Pos ) |\n            ( RADIO_PCNF1_ENDIAN_Little << RADIO_PCNF1_ENDIAN_Pos ) |\n            ( 3 << RADIO_PCNF1_BALEN_Pos ) |\n            ( 0 << RADIO_PCNF1_STATLEN_Pos );\n\n        nrf_radio->TXADDRESS = 0;\n        nrf_radio->RXADDRESSES = 1 << 0;\n\n        nrf_radio->CRCCNF    =\n            ( RADIO_CRCCNF_LEN_Three << RADIO_CRCCNF_LEN_Pos ) |\n            ( RADIO_CRCCNF_SKIPADDR_Skip << RADIO_CRCCNF_SKIPADDR_Pos );\n\n        // clear all used PPI pre-programmed channels (16.1.1)\n        nrf_ppi->CHENCLR = all_preprogramed_ppi_channels_mask;\n\n        // The polynomial has the form of x^24 +x^10 +x^9 +x^6 +x^4 +x^3 +x+1\n        nrf_radio->CRCPOLY   = 0x100065B;\n\n        // TIFS is only enforced if END_DISABLE and DISABLED_TXEN shortcuts are enabled.\n        nrf_radio->TIFS      = 150;\n    }\n\n    static void configure_timer_for_1us( NRF_TIMER_Type& timer )\n    {\n        timer.MODE        = TIMER_MODE_MODE_Timer << TIMER_MODE_MODE_Pos;\n        timer.BITMODE     = TIMER_BITMODE_BITMODE_32Bit;\n        timer.PRESCALER   = timer_prescale_for_1us_resolution;\n\n        timer.TASKS_STOP  = 1;\n        timer.TASKS_CLEAR = 1;\n        timer.EVENTS_COMPARE[ 0 ] = 0;\n        timer.EVENTS_COMPARE[ 1 ] = 0;\n        timer.EVENTS_COMPARE[ 2 ] = 0;\n        timer.EVENTS_COMPARE[ 3 ] = 0;\n    }\n\n    static void init_timer()\n    {\n        configure_timer_for_1us( *nrf_timer );\n    }\n\n    static void init_ppi()\n    {\n        assign_channel(\n            rtc_start_hfxo_ppi_channel,\n            nrf_rtc->EVENTS_COMPARE[ rtc_cc_start_hfxo ],\n            nrf_clock->TASKS_HFCLKSTART );\n    }\n\n    static void* instance = nullptr;\n    static void (*isr_handler)( void* );\n\n    static void enable_interrupts( void (*isr)( void* ), void* that )\n    {\n        instance    = that;\n        isr_handler = isr;\n\n        NVIC_SetPriority( RADIO_IRQn, nrf_interrupt_prio_ble );\n        NVIC_ClearPendingIRQ( RADIO_IRQn );\n        NVIC_EnableIRQ( RADIO_IRQn );\n    }\n\n    static unsigned frequency_from_channel( unsigned channel )\n    {\n        assert( channel < 40 );\n\n        if ( channel <= 10 )\n            return 4 + 2 * channel;\n\n        if ( channel <= 36 )\n            return 6 + 2 * channel;\n\n        if ( channel == 37 )\n            return 2;\n\n        if ( channel == 38 )\n            return 26;\n\n        return 80;\n    }\n\n    //////////////////////////////////////////\n    // class counter\n    counter::counter()\n        : low( 0 )\n        , high( 0 )\n    {\n    }\n\n    void counter::increment()\n    {\n        ++low;\n\n        if ( low == 0 )\n            ++high;\n    }\n\n    void counter::copy_to( std::uint8_t* target ) const\n    {\n        target  = details::write_32bit( target, low );\n        *target = high;\n    }\n\n    //////////////////////////////////////////\n    // class radio_hardware_without_crypto_support\n    void radio_hardware_without_crypto_support::init( void (*isr)( void* ), void* that )\n    {\n        init_debug();\n\n        init_radio( false );\n        init_timer();\n        init_ppi();\n\n        receive_2mbit_  = false;\n        transmit_2mbit_ = false;\n\n        enable_interrupts( isr, that );\n    }\n\n    void radio_hardware_without_crypto_support::configure_radio_channel( unsigned channel )\n    {\n        // When the radio is ramping up for transmitting or reception and is then disabled,\n        // the next state would be TXDISABLE or RXDISABLE. Wait till the radio safetely\n        // entered DISABLED state\n        while ((nrf_radio->STATE & RADIO_STATE_STATE_Msk) != RADIO_STATE_STATE_Disabled);\n\n        nrf_radio->FREQUENCY   = frequency_from_channel( channel );\n        nrf_radio->DATAWHITEIV = channel & 0x3F;\n\n        nrf_radio->INTENCLR    = 0xffffffff;\n    }\n\n    static void config_phy( bool transmit_2mbit )\n    {\n        nrf_radio->MODE        =\n            ( transmit_2mbit ? RADIO_MODE_MODE_Ble_2Mbit : RADIO_MODE_MODE_Ble_1Mbit ) << RADIO_MODE_MODE_Pos;\n\n        nrf_radio->PCNF0 = ( nrf_radio->PCNF0 & ~RADIO_PCNF0_PLEN_Msk )\n            | ( ( transmit_2mbit ? RADIO_PCNF0_PLEN_16bit : RADIO_PCNF0_PLEN_8bit ) << RADIO_PCNF0_PLEN_Pos );\n    }\n\n    void radio_hardware_without_crypto_support::configure_transmit_train(\n        const bluetoe::link_layer::write_buffer&    transmit_data )\n    {\n        config_phy( transmit_2mbit_ );\n\n        nrf_radio->SHORTS      =\n            RADIO_SHORTS_READY_START_Msk\n          | RADIO_SHORTS_END_DISABLE_Msk\n          | RADIO_SHORTS_DISABLED_RXEN_Msk\n          | RADIO_SHORTS_ADDRESS_BCSTART_Msk;\n\n        nrf_ppi->CHENCLR = all_preprogramed_ppi_channels_mask;\n        nrf_ppi->CHENSET =\n            ( 1 << radio_end_capture2_ppi_channel );\n\n        nrf_radio->EVENTS_PAYLOAD = 0;\n        nrf_radio->EVENTS_DISABLED = 0;\n\n        nrf_radio->PACKETPTR   = reinterpret_cast< std::uint32_t >( transmit_data.buffer );\n        nrf_radio->PCNF1       = ( nrf_radio->PCNF1 & ~RADIO_PCNF1_MAXLEN_Msk ) | ( transmit_data.size << RADIO_PCNF1_MAXLEN_Pos );\n    }\n\n    void radio_hardware_without_crypto_support::configure_final_transmit(\n        const bluetoe::link_layer::write_buffer&    transmit_data )\n    {\n        assert( transmit_data.buffer );\n\n        nrf_ppi->CHENCLR  = all_preprogramed_ppi_channels_mask;\n\n        nrf_radio->PACKETPTR   = reinterpret_cast< std::uint32_t >( transmit_data.buffer );\n        nrf_radio->PCNF1       = ( nrf_radio->PCNF1 & ~RADIO_PCNF1_MAXLEN_Msk ) | ( transmit_data.size << RADIO_PCNF1_MAXLEN_Pos );\n    }\n\n    void radio_hardware_without_crypto_support::configure_receive_train(\n        const bluetoe::link_layer::read_buffer& receive_buffer )\n    {\n        config_phy( receive_2mbit_ );\n\n        nrf_radio->SHORTS      =\n            RADIO_SHORTS_READY_START_Msk\n          | RADIO_SHORTS_END_DISABLE_Msk\n          | RADIO_SHORTS_DISABLED_TXEN_Msk;\n\n        nrf_ppi->CHENCLR = all_preprogramed_ppi_channels_mask;\n        nrf_ppi->CHENSET       =\n              ( 1 << compare0_rxen_ppi_channel )\n            | ( 1 << compare1_disable_ppi_channel )\n            | ( 1 << radio_end_capture2_ppi_channel );\n\n        nrf_timer->EVENTS_COMPARE[ 0 ] = 0;\n        nrf_timer->EVENTS_COMPARE[ 1 ] = 0;\n        nrf_radio->EVENTS_PAYLOAD = 0;\n\n        nrf_radio->PACKETPTR   = reinterpret_cast< std::uint32_t >( receive_buffer.buffer );\n        nrf_radio->PCNF1       = ( nrf_radio->PCNF1 & ~RADIO_PCNF1_MAXLEN_Msk ) | ( receive_buffer.size << RADIO_PCNF1_MAXLEN_Pos );\n    }\n\n    void radio_hardware_without_crypto_support::stop_radio()\n    {\n        // disable interrupts\n        nrf_radio->INTENCLR      = RADIO_INTENCLR_DISABLED_Msk;\n\n        // Stop timer, which also could cause interrupts by disabling the radio\n        nrf_timer->TASKS_STOP    = 1;\n        nrf_timer->TASKS_CLEAR   = 1;\n\n        // disconnect radio from all event sources\n        nrf_ppi->CHENCLR         = all_radio_ppi_channels_mask;\n        nrf_radio->SHORTS        = 0;\n\n        // disable radio\n        nrf_radio->TASKS_DISABLE = 1;\n\n        // consume event to not fire, once the radio is enabled again\n        bluetoe::nrf::nrf_radio->EVENTS_DISABLED  = 0;\n        NVIC_ClearPendingIRQ( RADIO_IRQn );\n    }\n\n    void radio_hardware_without_crypto_support::store_timer_anchor( int offset_us )\n    {\n        hf_connection_event_anchor_ = static_cast< int >( nrf_timer->CC[ tim_cc_capture_anchor ] ) + offset_us;\n        lf_connection_event_anchor_ = nrf_rtc->CC[ rtc_cc_start_timer ];\n\n        user_timer_anchor_moved_ = true;\n    }\n\n    std::tuple< bool, bool, bool > radio_hardware_without_crypto_support::received_pdu()\n    {\n        const bool result = ( nrf_radio->CRCSTATUS & RADIO_CRCSTATUS_CRCSTATUS_Msk ) == RADIO_CRCSTATUS_CRCSTATUS_CRCOk && nrf_radio->EVENTS_PAYLOAD;\n        nrf_radio->EVENTS_PAYLOAD = 0;\n\n        return { result, result, result };\n    }\n\n    std::uint32_t radio_hardware_without_crypto_support::now()\n    {\n        std::uint32_t counter = nrf_rtc->COUNTER;\n\n        if ( counter < lf_connection_event_anchor_ )\n            counter += 0x1000000;\n\n        const std::uint32_t anchor  = static_cast< std::int64_t >( lf_connection_event_anchor_ ) * 1000000 / nrf::lfxo_clk_freq + hf_connection_event_anchor_;\n        const std::uint32_t current = static_cast< std::uint64_t >( counter ) * 1000000 / nrf::lfxo_clk_freq;\n\n        // due to the lower resolution of current, current could possibly before anchor\n        return anchor < current\n            ? current - anchor\n            : 0;\n    }\n\n    std::pair< bool, link_layer::delta_time > radio_hardware_without_crypto_support::can_stop_connection_event_timer( std::uint32_t safety_margin_us )\n    {\n        // the function must decide whether it is possible to stop the setup connection event before the\n        // PPI machinery starts the high frequency oscilator. The decission has better to be on the\n        // safe side, as otherwise, the radio might start transmitting unspecified content.\n        const std::uint32_t counter = nrf_rtc->COUNTER;\n        const std::uint32_t plan    = nrf_rtc->CC[ rtc_cc_start_hfxo ];\n\n        // if counter > plan, then either the osc. was already started, or the counter wraped around\n        const std::uint32_t distance = counter >= plan\n            ? 0x1000000 + plan - counter\n            : plan - counter;\n\n        // if distance is larger that half the counter width, we probably have not a counter wrap\n        if ( distance > 0x800000 )\n            return { false, link_layer::delta_time() };\n\n        const std::uint64_t time = static_cast< std::uint64_t >( distance ) * 1000000 / nrf::lfxo_clk_freq;\n\n        // it is essentional to not underestimate the time from the anchor, otherwise, the setup of the\n        // connection event will fail and result in a timeout, which would lead to an additional delay of\n        // a interval.\n        if ( time > safety_margin_us )\n            return { true, link_layer::delta_time( now() + safety_margin_us ) };\n\n        return { false, link_layer::delta_time() };\n    }\n\n    void radio_hardware_without_crypto_support::set_phy(\n        bluetoe::link_layer::phy_ll_encoding::phy_ll_encoding_t receiving_encoding,\n        bluetoe::link_layer::phy_ll_encoding::phy_ll_encoding_t transmiting_encoding )\n    {\n        if ( receiving_encoding != bluetoe::link_layer::phy_ll_encoding::le_unchanged_coding )\n            receive_2mbit_ = receiving_encoding == bluetoe::link_layer::phy_ll_encoding::le_2m_phy;\n\n        if ( transmiting_encoding != bluetoe::link_layer::phy_ll_encoding::le_unchanged_coding )\n            transmit_2mbit_ = transmiting_encoding == bluetoe::link_layer::phy_ll_encoding::le_2m_phy;\n    }\n\n    static void setup_long_distance_timer(\n        const int           hf_anchor,\n        const std::uint32_t lf_anchor,\n        const std::uint32_t us_radio_start_time,\n        const std::uint32_t us_radio_startup_delay,\n        const std::uint32_t us_radio_timeout,\n        const bool          transmit,\n        const std::uint32_t start_hfxo_offset )\n    {\n        // Stop timer, stop HFXO\n        nrf_timer->TASKS_STOP = 1;\n        nrf_timer->TASKS_CLEAR = 1;\n\n        nrf_rtc->EVENTS_COMPARE[ rtc_cc_start_timer ] = 0;\n        nrf_rtc->EVENTS_COMPARE[ rtc_cc_start_hfxo ] = 0;\n        nrf_clock->EVENTS_HFCLKSTARTED = 0;\n        nrf_timer->EVENTS_COMPARE[ tim_cc_start_radio ] = 0;\n        nrf_timer->EVENTS_COMPARE[ tim_cc_timeout ] = 0;\n\n        // This time in the LFCLK domain corresponds with 0 in the HFCLK domain\n        const std::uint32_t rtc_tim_start_time  = lf_anchor;\n\n        // -1 to prevent the calculation to endup with starting the Radio at TIMER0 beeing 0\n        static constexpr auto us_offset   = 1;\n\n        // This is the radio start time in the HFCLK domain, that is start_radio_time µs after rtc_tim_start_time\n        // in the LFCLK domain.\n        const std::uint32_t start_radio_time = hf_anchor + us_radio_start_time - us_radio_startup_delay - us_offset;\n\n        // TODO: Optimize devision expressions for size\n        const std::uint32_t lf_start_radio_time =\n          static_cast< std::uint64_t >( start_radio_time )\n        * static_cast< std::uint64_t >( nrf::lfxo_clk_freq ) / 1000000;\n\n        const std::uint32_t hf_start_radio_time = start_radio_time -\n          static_cast< std::uint64_t >( lf_start_radio_time )\n        * static_cast< std::uint64_t >( 1000000 ) / nrf::lfxo_clk_freq;\n\n        nrf_rtc->CC[ rtc_cc_start_timer ] = rtc_tim_start_time + lf_start_radio_time;\n        nrf_rtc->CC[ rtc_cc_start_hfxo ]  = nrf_rtc->CC[ rtc_cc_start_timer ] - start_hfxo_offset;\n\n        // +1 borrowed at the beginning of the caluculation to prevent this register from beeing 0\n        nrf_timer->CC[ tim_cc_start_radio ] = hf_start_radio_time + us_offset;\n        nrf_timer->CC[ tim_cc_timeout ]     = nrf_timer->CC[ tim_cc_start_radio ] + us_radio_startup_delay + us_radio_timeout;\n\n        nrf_ppi->CHENSET =\n            ( transmit ? transmit_ppi_channels : receive_ppi_channels )\n          | ( 1 << rtc0_start_tim_ppi_channel )\n          | ( 1 << rtc_start_hfxo_ppi_channel );\n\n        record_long_distance_timer( hf_anchor, lf_anchor, us_radio_start_time, us_radio_startup_delay, us_radio_timeout );\n    }\n\n    static void enable_radio_disabled_interrupt()\n    {\n        nrf_radio->EVENTS_DISABLED = 0;\n        nrf_radio->INTENSET = RADIO_INTENSET_DISABLED_Msk;\n    }\n\n    // TODO This will not work if Advertising is stopped for a larger amount of time. In this case\n    //      the HFXO will run. Do we need to change the interface?\n    bool radio_hardware_without_crypto_support::schedule_advertisment_event_timer(\n        bluetoe::link_layer::delta_time when,\n        std::uint32_t                   read_timeout_us,\n        std::uint32_t                   start_hfxo_offset )\n    {\n        if ( when.zero() )\n        {\n            // capture the current time as anchor for the next advertisment\n            nrf_timer->TASKS_CAPTURE[ tim_cc_start_radio ] = 1;\n            nrf_rtc->CC[ rtc_cc_start_timer ] = nrf_rtc->COUNTER;\n\n            // immediately start the radio\n            nrf_timer->TASKS_START = 1;\n            nrf_timer->TASKS_CAPTURE[ tim_cc_timeout ]  = 1;\n            nrf_timer->CC[ tim_cc_timeout ]            += us_radio_tx_startup_time + read_timeout_us;\n\n            nrf_radio->TASKS_TXEN                       = 1;\n        }\n        else\n        {\n            // We need at least ~2ms to use this machinery\n            assert( when.usec() > 2000 );\n\n            // The Radio was planned to be started at this point, which is the anchor for the next\n            // advertising\n            const std::uint32_t hf_anchor = nrf_timer->CC[ tim_cc_start_radio ] + us_radio_tx_startup_time;\n            const std::uint32_t lf_anchor = nrf_rtc->CC[ rtc_cc_start_timer ];\n\n            setup_long_distance_timer(\n                hf_anchor, lf_anchor, when.usec(), us_radio_tx_startup_time, read_timeout_us, true, start_hfxo_offset );\n        }\n\n        enable_radio_disabled_interrupt();\n\n        return !when.zero();\n    }\n\n    void radio_hardware_without_crypto_support::schedule_connection_event_timer(\n        std::uint32_t                   begin_us,\n        std::uint32_t                   end_us,\n        std::uint32_t                   start_hfxo_offset )\n    {\n        setup_long_distance_timer(\n            hf_connection_event_anchor_,\n            lf_connection_event_anchor_,\n            begin_us, us_radio_rx_startup_time, end_us - begin_us, false, start_hfxo_offset );\n\n        enable_radio_disabled_interrupt();\n    }\n\n    static void (*user_timer_isr_handler)( void* );\n\n    bool radio_hardware_without_crypto_support::schedule_user_timer(\n        void (*isr)( void* ),\n        std::uint32_t                   time_us,\n        std::uint32_t                   max_cb_runtimer_ms )\n    {\n        // when this assert hits, the last callback took longer than declared\n        assert( !nrf_cb_timer->EVENTS_COMPARE[ cb_tim_cc_assert_end_cb ] );\n        assert( max_cb_runtimer_ms > 0 );\n\n        user_timer_isr_handler   = isr;\n        user_timer_anchor_moved_ = false;\n\n        // configure timer and PPI. If the user timer is not used, the application is free to use\n        // timer and PPI\n        configure_timer_for_1us( *nrf_cb_timer );\n        nrf_cb_timer->SHORTS   = TIMER_SHORTS_COMPARE1_STOP_Enabled << TIMER_SHORTS_COMPARE1_STOP_Pos;\n        nrf_cb_timer->INTENSET = TIMER_INTENSET_COMPARE0_Enabled << TIMER_INTENSET_COMPARE0_Pos;\n        nrf_rtc->EVTENSET = RTC_EVTEN_COMPARE2_Enabled << RTC_EVTEN_COMPARE2_Pos;\n\n        assign_channel( rtc_start_cb_timer_ppi_channel, nrf_rtc->EVENTS_COMPARE[ rtc_cc_start_cb_timer ], nrf_cb_timer->TASKS_START );\n        nrf_ppi->CHENSET = 1 << rtc_start_cb_timer_ppi_channel;\n\n        NVIC_SetPriority( TIMER1_IRQn, nrf_interrupt_prio_user_cb );\n        NVIC_ClearPendingIRQ( TIMER1_IRQn );\n        NVIC_EnableIRQ( TIMER1_IRQn );\n\n        int hf_anchor;\n        std::uint32_t lf_anchor;\n\n        {\n            lock_guard lock;\n            hf_anchor = hf_connection_event_anchor_;\n            lf_anchor = lf_connection_event_anchor_;\n        }\n\n        // -1 to prevent the calculation to endup with starting the Radio at TIMER1 beeing 0\n        static constexpr auto us_offset   = 1;\n\n        const std::uint32_t trigger_isr_time = hf_anchor + time_us - us_offset;\n\n        const std::uint32_t lf_call_cb_time =\n          static_cast< std::uint64_t >( trigger_isr_time )\n        * static_cast< std::uint64_t >( nrf::lfxo_clk_freq ) / 1000000;\n\n        const std::uint32_t hf_call_cb_time = trigger_isr_time -\n          static_cast< std::uint64_t >( lf_call_cb_time )\n        * static_cast< std::uint64_t >( 1000000 ) / nrf::lfxo_clk_freq;\n\n        nrf_rtc->CC[ rtc_cc_start_cb_timer ] = lf_anchor + lf_call_cb_time;\n\n        const auto counter = nrf_rtc->COUNTER;\n        static_cast< void >( counter );\n\n        assert( ( bluetoe::details::distance_n< 24u, std::uint32_t >( counter, nrf_rtc->CC[ rtc_cc_start_cb_timer ] ) > 0 ) );\n\n        nrf_cb_timer->CC[ cb_tim_cc_start_exec_cb ] = hf_call_cb_time + us_offset;\n        nrf_cb_timer->CC[ cb_tim_cc_assert_end_cb ] = nrf_cb_timer->CC[ cb_tim_cc_start_exec_cb ] + max_cb_runtimer_ms;\n\n        assert( nrf_cb_timer->CC[ cb_tim_cc_assert_end_cb ] > nrf_cb_timer->CC[ cb_tim_cc_start_exec_cb ] );\n\n        return true;\n    }\n\n    bool radio_hardware_without_crypto_support::stop_user_timer()\n    {\n        nrf_ppi->CHENCLR = 1 << rtc_start_cb_timer_ppi_channel;\n        nrf_cb_timer->INTENCLR = TIMER_INTENSET_COMPARE0_Enabled << TIMER_INTENSET_COMPARE0_Pos;\n        nrf_cb_timer->TASKS_STOP = 1;\n        nrf_cb_timer->INTENCLR = 0xFFFFFFFF;\n\n        const bool result = nrf_cb_timer->EVENTS_COMPARE[ cb_tim_cc_start_exec_cb ] == 0;\n        nrf_cb_timer->EVENTS_COMPARE[ cb_tim_cc_start_exec_cb ] = 0;\n\n        return result;\n    }\n\n    void radio_hardware_without_crypto_support::stop_timeout_timer()\n    {\n        nrf_ppi->CHENCLR = ( 1 << compare1_disable_ppi_channel );\n    }\n\n    std::uint32_t radio_hardware_without_crypto_support::static_random_address_seed()\n    {\n        return NRF_FICR->DEVICEID[ 0 ];\n    }\n\n    void radio_hardware_without_crypto_support::set_access_address_and_crc_init( std::uint32_t access_address, std::uint32_t crc_init )\n    {\n        nrf_radio->BASE0     = ( access_address << 8 ) & 0xFFFFFF00;\n        nrf_radio->PREFIX0   = ( access_address >> 24 ) & RADIO_PREFIX0_AP0_Msk;\n        nrf_radio->CRCINIT   = crc_init;\n    }\n\n    void radio_hardware_without_crypto_support::debug_toggle()\n    {\n        toggle_debug_pin();\n    }\n\n    bool radio_hardware_without_crypto_support::user_timer_anchor_moved()\n    {\n        bool result = user_timer_anchor_moved_;\n        user_timer_anchor_moved_ = false;\n\n        return result;\n    }\n\n    bool                   radio_hardware_without_crypto_support::receive_2mbit_;\n    bool                   radio_hardware_without_crypto_support::transmit_2mbit_;\n    volatile int           radio_hardware_without_crypto_support::hf_connection_event_anchor_;\n    volatile std::uint32_t radio_hardware_without_crypto_support::lf_connection_event_anchor_;\n    volatile bool          radio_hardware_without_crypto_support::user_timer_anchor_moved_;\n\n    //////////////////////////////////////////////\n    // class radio_hardware_with_crypto_support\n    static constexpr std::size_t ccm_key_offset = 0;\n    static constexpr std::size_t ccm_packet_counter_offset = 16;\n    static constexpr std::size_t ccm_packet_counter_size   = 5;\n    static constexpr std::size_t ccm_direction_offset = 24;\n    static constexpr std::size_t ccm_iv_offset  = 25;\n\n    static constexpr std::uint8_t central_to_peripheral_ccm_direction = 0x01;\n    static constexpr std::uint8_t peripheral_to_central_ccm_direction = 0x00;\n\n    // the value MAXPACKETSIZE from the documentation seems to be the maximum value, the size field can store,\n    // and is independent from the MTU size (https://devzone.nordicsemi.com/f/nordic-q-a/13123/what-is-actual-size-required-for-scratch-area-for-ccm-on-nrf52/50031#50031)\n    static constexpr std::size_t scratch_size   = 267;\n\n    static struct alignas( 4 ) ccm_data_struct_t {\n        std::uint8_t data[ 33 ];\n    } ccm_data_struct;\n\n    static struct alignas( 4 ) scratch_area_t {\n        std::uint8_t data[ scratch_size ];\n    } scratch_area;\n\n    static void setup_ccm_data_structure( const bluetoe::details::uint128_t& key, std::uint64_t IV )\n    {\n        std::copy( key.rbegin(), key.rend(), &ccm_data_struct.data[ ccm_key_offset ] );\n        std::fill( &ccm_data_struct.data[ ccm_packet_counter_offset ],\n            &ccm_data_struct.data[ ccm_packet_counter_offset + ccm_packet_counter_size ], 0 );\n\n        details::write_64bit( &ccm_data_struct.data[ ccm_iv_offset ], IV );\n    }\n\n    void radio_hardware_with_crypto_support::init( std::uint8_t* encrypted_area, void (*isr)( void* ), void* that )\n    {\n        init_debug();\n\n        encrypted_area_ = encrypted_area;\n\n        init_radio( true );\n        init_timer();\n        init_ppi();\n\n        enable_interrupts( isr, that );\n\n        nrf_random->CONFIG  = RNG_CONFIG_DERCEN_Msk;\n        nrf_random->SHORTS  = RNG_SHORTS_VALRDY_STOP_Msk;\n\n        nrf_ccm->SCRATCHPTR = reinterpret_cast< std::uintptr_t >( &scratch_area );\n        nrf_ccm->CNFPTR     = reinterpret_cast< std::uintptr_t >( &ccm_data_struct );\n\n        configure_encryption( false, false );\n    }\n\n    void radio_hardware_with_crypto_support::configure_transmit_train(\n        const bluetoe::link_layer::write_buffer&    transmit_data )\n    {\n        config_phy( transmit_2mbit_ );\n\n        nrf_radio->SHORTS      =\n            RADIO_SHORTS_READY_START_Msk\n          | RADIO_SHORTS_END_DISABLE_Msk\n          | RADIO_SHORTS_DISABLED_RXEN_Msk\n          | RADIO_SHORTS_ADDRESS_BCSTART_Msk;\n\n        nrf_ppi->CHENCLR = all_preprogramed_ppi_channels_mask;\n        nrf_ppi->CHENSET =\n            ( 1 << radio_end_capture2_ppi_channel );\n\n        nrf_radio->EVENTS_PAYLOAD = 0;\n        nrf_radio->EVENTS_DISABLED = 0;\n\n        nrf_radio->PACKETPTR   = reinterpret_cast< std::uint32_t >( transmit_data.buffer );\n        nrf_radio->PCNF1       =\n            ( nrf_radio->PCNF1 & ~RADIO_PCNF1_MAXLEN_Msk )\n          | ( ( transmit_data.size - 1 ) << RADIO_PCNF1_MAXLEN_Pos );\n    }\n\n    void radio_hardware_with_crypto_support::configure_final_transmit(\n        const bluetoe::link_layer::write_buffer&    transmit_data )\n    {\n        nrf_ppi->CHENCLR        = all_preprogramed_ppi_channels_mask;\n\n        // only encrypt none empty PDUs\n        if ( transmit_encrypted_ && transmit_data.buffer[ 1 ] != 0 )\n        {\n            transmit_counter_.copy_to( &ccm_data_struct.data[ ccm_packet_counter_offset ] );\n            ccm_data_struct.data[ ccm_direction_offset ] = peripheral_to_central_ccm_direction;\n\n            nrf_ccm->SHORTS  = CCM_SHORTS_ENDKSGEN_CRYPT_Msk;\n            nrf_ccm->MODE    =\n                  ( CCM_MODE_MODE_Encryption << CCM_MODE_MODE_Pos )\n                | ( CCM_MODE_LENGTH_Extended << CCM_MODE_LENGTH_Pos )\n                | ( ( transmit_2mbit_ ? CCM_MODE_DATARATE_2Mbit : CCM_MODE_DATARATE_1Mbit ) << CCM_MODE_DATARATE_Pos );\n            nrf_ccm->OUTPTR     = reinterpret_cast< std::uint32_t >( encrypted_area_ );\n            nrf_ccm->INPTR      = reinterpret_cast< std::uint32_t >( transmit_data.buffer );\n            nrf_ccm->SCRATCHPTR = reinterpret_cast< std::uintptr_t >( &scratch_area );\n\n            nrf_ccm->EVENTS_ENDKSGEN    = 0;\n            nrf_ccm->EVENTS_ENDCRYPT    = 0;\n\n            nrf_radio->PACKETPTR = reinterpret_cast< std::uint32_t >( encrypted_area_ );\n            nrf_radio->PCNF1 =\n                ( nrf_radio->PCNF1 & ~RADIO_PCNF1_MAXLEN_Msk )\n              | ( ( transmit_data.size + encryption_mic_size - 1 ) << RADIO_PCNF1_MAXLEN_Pos );\n\n            nrf_ccm->TASKS_KSGEN        = 1;\n        }\n        else\n        {\n            nrf_radio->PACKETPTR    = reinterpret_cast< std::uint32_t >( transmit_data.buffer );\n            nrf_radio->PCNF1        =\n                ( nrf_radio->PCNF1 & ~RADIO_PCNF1_MAXLEN_Msk )\n              | ( ( transmit_data.size - 1 ) << RADIO_PCNF1_MAXLEN_Pos );\n        }\n    }\n\n    void radio_hardware_with_crypto_support::configure_receive_train(\n        const bluetoe::link_layer::read_buffer&     receive_buffer )\n    {\n        config_phy( receive_2mbit_ );\n\n        if ( receive_encrypted_ )\n        {\n            receive_counter_.copy_to( &ccm_data_struct.data[ ccm_packet_counter_offset ] );\n            ccm_data_struct.data[ ccm_direction_offset ] = central_to_peripheral_ccm_direction;\n\n            // Reseting the CCM before every connection event seems to workaround a bug that\n            // Causes the CCM to start decrypting an incomming PDU, before it was actually received\n            // which causes overwriting the receive buffer, if the length field in the encrypted_area_\n            // was long enough.\n            // (https://devzone.nordicsemi.com/f/nordic-q-a/43656/what-causes-decryption-before-receiving)\n            nrf_ccm->ENABLE = CCM_ENABLE_ENABLE_Disabled;\n            nrf_ccm->ENABLE = CCM_ENABLE_ENABLE_Enabled;\n            nrf_ccm->MODE   =\n                  ( CCM_MODE_MODE_Decryption << CCM_MODE_MODE_Pos )\n                | ( CCM_MODE_LENGTH_Extended << CCM_MODE_LENGTH_Pos )\n                | ( ( receive_2mbit_ ? CCM_MODE_DATARATE_2Mbit : CCM_MODE_DATARATE_1Mbit ) << CCM_MODE_DATARATE_Pos );\n            nrf_ccm->CNFPTR     = reinterpret_cast< std::uintptr_t >( &ccm_data_struct );\n            nrf_ccm->INPTR      = reinterpret_cast< std::uint32_t >( encrypted_area_ );\n            nrf_ccm->OUTPTR     = reinterpret_cast< std::uint32_t >( receive_buffer.buffer );\n            nrf_ccm->SCRATCHPTR = reinterpret_cast< std::uintptr_t >( &scratch_area );\n            nrf_ccm->SHORTS     = 0;\n            nrf_ccm->EVENTS_ENDKSGEN = 0;\n            nrf_ccm->EVENTS_ENDCRYPT = 0;\n            nrf_ccm->EVENTS_ERROR = 0;\n\n            // Maximum package payload size is, the buffer size minus the LL header and the one reserve\n            // byte that is required by the nrf52 radio hardware:\n            static constexpr std::size_t radio_pdu_to_payload_overhead = 3;\n            nrf_ccm->MAXPACKETSIZE= receive_buffer.size - radio_pdu_to_payload_overhead;\n\n            nrf_ccm->TASKS_KSGEN = 1;\n        }\n\n        static constexpr std::uint32_t radio_shorts =\n            RADIO_SHORTS_READY_START_Msk\n          | RADIO_SHORTS_END_DISABLE_Msk\n          | RADIO_SHORTS_DISABLED_TXEN_Msk;\n\n        static constexpr std::uint32_t encrypted_ppi_channels =\n            ( 1 << radio_address_ccm_crypt )\n          | ( 1 << compare0_rxen_ppi_channel )\n          | ( 1 << compare1_disable_ppi_channel )\n          | ( 1 << radio_end_capture2_ppi_channel );\n\n        static constexpr std::uint32_t unencrypted_ppi_channels =\n            ( 1 << compare0_rxen_ppi_channel )\n          | ( 1 << compare1_disable_ppi_channel )\n          | ( 1 << radio_end_capture2_ppi_channel );\n\n        nrf_radio->SHORTS   = radio_shorts;\n        nrf_ppi->CHENCLR    = all_preprogramed_ppi_channels_mask;\n        nrf_ppi->CHENSET    = receive_encrypted_\n            ? encrypted_ppi_channels\n            : unencrypted_ppi_channels;\n\n        nrf_timer->EVENTS_COMPARE[ 0 ] = 0;\n        nrf_timer->EVENTS_COMPARE[ 1 ] = 0;\n        nrf_radio->EVENTS_PAYLOAD = 0;\n\n        const auto mic_size = []( bool receive_encrypted ){\n            return receive_encrypted\n                ? encryption_mic_size\n                : 0;\n        };\n\n        nrf_radio->PACKETPTR   = receive_encrypted_\n            ? reinterpret_cast< std::uint32_t >( encrypted_area_ )\n            : reinterpret_cast< std::uint32_t >( receive_buffer.buffer );\n\n        nrf_radio->PCNF1       =\n            ( nrf_radio->PCNF1 & ~RADIO_PCNF1_MAXLEN_Msk )\n          | ( ( receive_buffer.size + mic_size( receive_encrypted_ ) ) << RADIO_PCNF1_MAXLEN_Pos );\n    }\n\n    void radio_hardware_with_crypto_support::store_timer_anchor( int offset_us )\n    {\n        // TODO: Hack is required, as we capture the Anchor at the END of the PDU\n        // Issue: #76 Taking Anchor from End of PDU\n        if ( receive_encrypted_ && offset_us < -80 )\n            offset_us -= encryption_mic_size * 8;\n\n        radio_hardware_without_crypto_support::store_timer_anchor( offset_us );\n    }\n\n    std::tuple< bool, bool, bool > radio_hardware_with_crypto_support::received_pdu()\n    {\n        const auto receive_size = [](){\n            return reinterpret_cast< const std::uint8_t* >( nrf_radio->PACKETPTR )[ 1 ];\n        };\n\n        const bool timeout      = ( nrf_radio->CRCSTATUS & RADIO_CRCSTATUS_CRCSTATUS_Msk ) != RADIO_CRCSTATUS_CRCSTATUS_CRCOk || !nrf_radio->EVENTS_PAYLOAD;\n        const bool crc_error    = !timeout && ( nrf_radio->CRCSTATUS & RADIO_CRCSTATUS_CRCSTATUS_Msk ) != RADIO_CRCSTATUS_CRCSTATUS_CRCOk;\n        const bool mic_error    = receive_encrypted_ && receive_size() != 0 && ( nrf_ccm->MICSTATUS & CCM_MICSTATUS_MICSTATUS_Msk ) == CCM_MICSTATUS_MICSTATUS_CheckFailed;\n        const bool bus_error    = receive_encrypted_ && nrf_ccm->EVENTS_ERROR;\n        const bool not_decrypt  = receive_encrypted_ && receive_size() != 0 && nrf_ccm->EVENTS_ENDCRYPT == 0;\n\n        const bool valid_anchor = !timeout && !bus_error;\n        const bool valid_pdu    = valid_anchor && !crc_error && !not_decrypt && !mic_error;\n\n        nrf_radio->EVENTS_PAYLOAD = 0;\n\n        return { valid_anchor, valid_pdu, !crc_error };\n    }\n\n    void radio_hardware_with_crypto_support::configure_encryption( bool receive, bool transmit )\n    {\n        if ( receive && transmit )\n            transmit_counter_ = counter();\n\n        if ( receive && !transmit )\n            receive_counter_ = counter();\n\n        if ( !receive && !transmit )\n        {\n            // delete key out of memory\n            std::memset( &ccm_data_struct, 0, sizeof( ccm_data_struct ) );\n            nrf_ccm->ENABLE = nrf_ccm->ENABLE & ~CCM_ENABLE_ENABLE_Msk;\n        }\n\n        receive_encrypted_ = receive;\n        transmit_encrypted_ = transmit;\n    }\n\n    std::pair< std::uint64_t, std::uint32_t > radio_hardware_with_crypto_support::setup_encryption( bluetoe::details::uint128_t key, std::uint64_t skdm, std::uint32_t ivm )\n    {\n        const std::uint64_t skds = random_number64();\n        const std::uint32_t ivs  = random_number32();\n\n        bluetoe::details::uint128_t session_descriminator;\n        details::write_64bit( &session_descriminator[ 0 ], skdm );\n        details::write_64bit( &session_descriminator[ 8 ], skds );\n\n        setup_ccm_data_structure(\n            aes_le( key, session_descriminator ),\n            static_cast< std::uint64_t >( ivm ) | ( static_cast< std::uint64_t >( ivs ) << 32 ) );\n\n        return { skds, ivs };\n    }\n\n    void radio_hardware_with_crypto_support::setup_identity_resolving_address(\n        const std::uint8_t* address )\n    {\n        if ( identity_resolving_enabled_ )\n        {\n            nrf_aar->EVENTS_END         = 0;\n            nrf_aar->EVENTS_RESOLVED    = 0;\n            nrf_aar->EVENTS_NOTRESOLVED = 0;\n\n            nrf_aar->ADDRPTR = reinterpret_cast< std::uint32_t >( address ) ;\n        }\n    }\n\n    void radio_hardware_with_crypto_support::set_identity_resolving_key(\n        const details::identity_resolving_key_t& irk )\n    {\n        static details::identity_resolving_key_t irk_storage;\n        irk_storage = irk;\n\n        identity_resolving_enabled_ = true;\n\n        // disable CCM\n        nrf_ccm->ENABLE   = CCM_ENABLE_ENABLE_Disabled;\n        nrf_ccm->INTENCLR = 0xFFFFFFFF;\n        nrf_ppi->CHENCLR  = ( 1 << radio_address_ccm_crypt );\n\n        // setup AAR\n        nrf_ppi->CHENSET    = ( 1 << radio_bcmatch_aar_start_channel );\n        nrf_radio->BCC      = 16 + 2 * ( 6 * 8 );\n        nrf_aar->SCRATCHPTR = reinterpret_cast< std::uintptr_t >( &scratch_area );\n        nrf_aar->IRKPTR     = reinterpret_cast< std::uint32_t >( &irk_storage );\n        nrf_aar->NIRK       = 1;\n\n        nrf_aar->ENABLE     = AAR_ENABLE_ENABLE_Msk;\n    }\n\n    bool radio_hardware_with_crypto_support::resolving_address_invalid()\n    {\n        if ( identity_resolving_enabled_ )\n        {\n            while ( !nrf_aar->EVENTS_END )\n                ;\n\n            if ( nrf_aar->EVENTS_NOTRESOLVED )\n                return true;\n        }\n\n        return false;\n    }\n\n    volatile bool radio_hardware_with_crypto_support::receive_encrypted_  = false;\n    volatile bool radio_hardware_with_crypto_support::transmit_encrypted_ = false;\n    std::uint8_t* radio_hardware_with_crypto_support::encrypted_area_;\n    counter radio_hardware_with_crypto_support::transmit_counter_;\n    counter radio_hardware_with_crypto_support::receive_counter_;\n    bool    radio_hardware_with_crypto_support::identity_resolving_enabled_ = false;\n\n    // Problem: The HFXO is required by the radio and by the calibration.\n    // For the Radio, the HFXO is requested by an RTC event. So there is no mean, to\n    // increment some kind of usage counter that could be used to defere the disabling\n    // of the HFXO if one of the two usages are still using the HFXO.\n\n    // Solution: Let the radio still start / stop the HFXO, but defere the stop to the\n    // next connection event, if the HFXO is still in use by the calibration.\n\n    // Design: nrf_clock->EVENTS_CTTO is used to indicate, that a calibration of the\n    // RC is requested. The calibration timeout does not start the HFXO, it's waited\n    // until the next connection events starts the HFXO. The HFXO is then stopped,\n    // by the end of a connection event, after the calibration was done.\n\n    // As there is a requirement, to have the calibration run at least every 8 seconds,\n    // and as the maximum advertising event is 4s, it is required to have the calibration\n    // running every 4s.\n    static constexpr std::uint32_t calibration_timer_counter = 4 * 4;\n    static bool calibration_running = false;\n\n    static std::uint32_t last_calibration_temp = 0;\n    static constexpr int calibration_temp_threshold = 2; // 0.5°\n\n    // this indirection leads to clock_calibrate_isr() not beeing linked in, if not used\n    static void (*clock_isr_handler)() = nullptr;\n    static void clock_calibrate_isr()\n    {\n        set_isr_pin();\n\n        // Calibration Timer Time Out\n        if ( nrf_clock->EVENTS_CTTO )\n        {\n            nrf_clock->INTENCLR = CLOCK_INTENSET_CTTO_Msk;\n        }\n\n        // Calibration timer timed out and HFXO is running\n        if ( nrf_clock->EVENTS_HFCLKSTARTED )\n        {\n            nrf_clock->EVENTS_HFCLKSTARTED = 0;\n\n            nrf_temp->EVENTS_DATARDY = 0;\n            nrf_temp->TASKS_START = 1;\n\n            if ( nrf_clock->EVENTS_CTTO && !calibration_running )\n            {\n                calibration_running = true;\n                nrf_clock->TASKS_CAL = 1;\n            }\n        }\n\n        // Calibration Done\n        if ( nrf_clock->EVENTS_DONE )\n        {\n            calibration_running = false;\n            nrf_clock->EVENTS_DONE = 0;\n            nrf_clock->EVENTS_CTTO = 0;\n            nrf_clock->INTENSET  = CLOCK_INTENSET_CTTO_Msk;\n\n            // Restart calibration timer\n            nrf_clock->CTIV = calibration_timer_counter;\n            nrf_clock->TASKS_CTSTART = 1;\n        }\n\n        reset_isr_pin();\n    }\n\n    void init_calibration_timer()\n    {\n        clock_isr_handler = clock_calibrate_isr;\n\n        nrf_clock->EVENTS_DONE = 0;\n        nrf_clock->EVENTS_CTTO = 0;\n        nrf_clock->EVENTS_HFCLKSTARTED = 0;\n\n        nrf_clock->INTENSET =\n            CLOCK_INTENSET_DONE_Msk\n          | CLOCK_INTENSET_CTTO_Msk\n          | CLOCK_INTENSET_HFCLKSTARTED_Msk;\n\n        NVIC_SetPriority( POWER_CLOCK_IRQn, nrf_interrupt_prio_calibrate_rtc );\n        NVIC_ClearPendingIRQ( POWER_CLOCK_IRQn );\n        NVIC_EnableIRQ( POWER_CLOCK_IRQn );\n\n        calibration_running = false;\n\n        nrf_clock->CTIV = 0;\n        nrf_clock->TASKS_CTSTART = 1;\n    }\n\n    void deassign_hfxo()\n    {\n        if ( nrf_clock->EVENTS_CTTO == 0 )\n        {\n            nrf_clock->TASKS_HFCLKSTOP = 1;\n            gpio_debug_hfxo_stopped();\n        }\n\n        if ( nrf_temp->EVENTS_DATARDY )\n        {\n            nrf_temp->EVENTS_DATARDY = 0;\n\n            const int current_temp = static_cast< int >( nrf_temp->TEMP );\n            const int diff = last_calibration_temp - current_temp;\n\n            if ( diff >= calibration_temp_threshold || diff <= -calibration_temp_threshold )\n            {\n                last_calibration_temp = current_temp;\n\n                // force a recalibration at the next connection event\n                nrf_clock->TASKS_CTSTOP = 1;\n                nrf_clock->CTIV = 0;\n                nrf_clock->TASKS_CTSTART = 1;\n            }\n        }\n    }\n} // namespace nrf52_details\n} // namespace bluetoe\n\nextern \"C\" void RADIO_IRQHandler(void)\n{\n    using namespace bluetoe::nrf52_details;\n    set_isr_pin();\n\n    assert( bluetoe::nrf::nrf_radio->EVENTS_DISABLED );\n    // High frequency clock is running and is running from the crystal oscilator\n    assert( ( bluetoe::nrf::nrf_clock->HFCLKSTAT & ( CLOCK_HFCLKSTAT_SRC_Msk | CLOCK_HFCLKSTAT_STATE_Msk ) )\n        == ( ( CLOCK_LFCLKSTAT_STATE_Running << CLOCK_LFCLKSTAT_STATE_Pos ) | ( CLOCK_LFCLKSTAT_SRC_Xtal << CLOCK_LFCLKSTAT_SRC_Pos ) ) );\n\n    assert( bluetoe::nrf52_details::instance );\n    assert( bluetoe::nrf52_details::isr_handler );\n    isr_handler( bluetoe::nrf52_details::instance );\n\n    bluetoe::nrf::nrf_radio->EVENTS_END       = 0;\n    bluetoe::nrf::nrf_radio->EVENTS_DISABLED  = 0;\n    bluetoe::nrf::nrf_radio->EVENTS_READY     = 0;\n    bluetoe::nrf::nrf_radio->EVENTS_ADDRESS   = 0;\n    bluetoe::nrf::nrf_radio->EVENTS_PAYLOAD   = 0;\n\n    reset_isr_pin();\n}\n\nextern \"C\" void POWER_CLOCK_IRQHandler()\n{\n    bluetoe::nrf52_details::clock_isr_handler();\n}\n\nextern \"C\" void TIMER1_IRQHandler()\n{\n    assert( bluetoe::nrf52_details::instance );\n    assert( bluetoe::nrf52_details::user_timer_isr_handler );\n\n    bluetoe::nrf::nrf_cb_timer->TASKS_STOP = 1;\n    bluetoe::nrf::nrf_cb_timer->INTENCLR = 0xFFFFFFFF;\n    bluetoe::nrf::nrf_cb_timer->EVENTS_COMPARE[ bluetoe::nrf52_details::cb_tim_cc_start_exec_cb ] = 0;\n\n    // the next timer is setup from within the callback,\n    // so better do not alter anything after this call\n    bluetoe::nrf52_details::user_timer_isr_handler( bluetoe::nrf52_details::instance );\n}\n"
  },
  {
    "path": "bluetoe/bindings/nordic/nrf52/security_tool_box.cpp",
    "content": "#include <cassert>\n#include <bluetoe/security_tool_box.hpp>\n#include <bluetoe/nrf.hpp>\n\n#include \"uECC.h\"\n\nnamespace bluetoe\n{\nusing namespace bluetoe::nrf;\n\nnamespace nrf52_details\n{\n    /////////////////////////////////\n    // class security_tool_box\n\n    // TODO: Entropie-Pool to not block here too much\n    // How much random numbers do we need:\n    //  - without encryption?\n    //  - encrytped but already paired? <-- this might be the sweetspot\n    //  - leagacy pairing?\n    //  - LESC pairing?\n    static std::uint8_t random_number8()\n    {\n        nrf_random->TASKS_START = 1;\n\n        while ( !nrf_random->EVENTS_VALRDY )\n            ;\n\n        nrf_random->EVENTS_VALRDY = 0;\n\n        return nrf_random->VALUE;\n    }\n\n    static std::uint16_t random_number16()\n    {\n        return static_cast< std::uint16_t >( random_number8() )\n            | ( static_cast< std::uint16_t >( random_number8() ) << 8 );\n    }\n\n    std::uint32_t random_number32()\n    {\n        return static_cast< std::uint32_t >( random_number16() )\n            | ( static_cast< std::uint32_t >( random_number16() ) << 16 );\n    }\n\n    std::uint64_t random_number64()\n    {\n        return static_cast< std::uint64_t >( random_number32() )\n            | ( static_cast< std::uint64_t >( random_number32() ) << 32 );\n    }\n\n    // Note: While every function above the link layer uses low to high byte order inputs to the\n    // EAS function, the CCM, that encrypts the link layer trafic, uses high to low byte order.\n    // That's why the intput and output in aes_le() changeing the byte order. The result of the\n    // key deversification is the key for the CCM algorithm and thus have to be stored in high to\n    // low byte order.\n\n    static bluetoe::details::uint128_t aes_le( const bluetoe::details::uint128_t& key, const std::uint8_t* data )\n    {\n        static struct alignas( 4 ) ecb_data_t {\n            std::uint8_t data[ 3 * 16 ];\n        } ecb_scratch_data;\n\n        nrf_aes->ECBDATAPTR = reinterpret_cast< std::uint32_t >( &ecb_scratch_data.data[ 0 ] );\n\n        std::copy( key.rbegin(), key.rend(), &ecb_scratch_data.data[ 0 ] );\n        std::reverse_copy( data, data + 16, &ecb_scratch_data.data[ 16 ] );\n\n        nrf_aes->TASKS_STARTECB = 1;\n\n        while ( !nrf_aes->EVENTS_ENDECB && !nrf_aes->EVENTS_ERRORECB )\n            ;\n\n        assert( !nrf_aes->EVENTS_ERRORECB );\n        nrf_aes->EVENTS_ENDECB = 0;\n\n        bluetoe::details::uint128_t result;\n        std::copy( &ecb_scratch_data.data[ 32 ], &ecb_scratch_data.data[ 48 ], result.rbegin() );\n\n        // erase key out of memory\n        std::fill( &ecb_scratch_data.data[ 0 ], &ecb_scratch_data.data[ 16 ], 0 );\n\n        return result;\n    }\n\n    bluetoe::details::uint128_t aes_le( const bluetoe::details::uint128_t& key, const bluetoe::details::uint128_t& data )\n    {\n        return aes_le( key, data.data() );\n    }\n\n    static bluetoe::details::uint128_t xor_( bluetoe::details::uint128_t a, const std::uint8_t* b )\n    {\n        std::transform(\n            a.begin(), a.end(),\n            b,\n            a.begin(),\n            []( std::uint8_t x, std::uint8_t y ) -> std::uint8_t\n            {\n                return x xor y;\n            }\n        );\n\n        return a;\n    }\n\n    static bluetoe::details::uint128_t xor_( bluetoe::details::uint128_t a, const bluetoe::details::uint128_t& b )\n    {\n        return xor_( a, b.data() );\n    }\n\n    bluetoe::details::uint128_t security_tool_box::create_srand()\n    {\n        details::uint128_t result;\n        std::generate( result.begin(), result.end(), random_number8 );\n\n        return result;\n    }\n\n    bluetoe::details::longterm_key_t security_tool_box::create_long_term_key()\n    {\n        const details::longterm_key_t result = {\n            create_srand(),\n            random_number64(),\n            random_number16()\n        };\n\n        return result;\n    }\n\n    bluetoe::details::uint128_t security_tool_box::c1(\n        const bluetoe::details::uint128_t& temp_key,\n        const bluetoe::details::uint128_t& rand,\n        const bluetoe::details::uint128_t& p1,\n        const bluetoe::details::uint128_t& p2 ) const\n    {\n        // c1 (k, r, preq, pres, iat, rat, ia, ra) = e(k, e(k, r XOR p1) XOR p2)\n        const auto p1_ = aes_le( temp_key, xor_( rand, p1 ) );\n\n        return aes_le( temp_key, xor_( p1_, p2 ) );\n    }\n\n    bluetoe::details::uint128_t security_tool_box::s1(\n        const bluetoe::details::uint128_t& temp_key,\n        const bluetoe::details::uint128_t& srand,\n        const bluetoe::details::uint128_t& mrand )\n    {\n        bluetoe::details::uint128_t r;\n        std::copy( &srand[ 0 ], &srand[ 8 ], &r[ 8 ] );\n        std::copy( &mrand[ 0 ], &mrand[ 8 ], &r[ 0 ] );\n\n        return aes_le( temp_key, r );\n    }\n\n    bool security_tool_box::is_valid_public_key( const std::uint8_t* public_key ) const\n    {\n        bluetoe::details::ecdh_public_key_t key;\n        std::reverse_copy(public_key, public_key + 32, key.begin());\n        std::reverse_copy(public_key + 32, public_key + 64, key.begin() + 32);\n\n        return uECC_valid_public_key( key.data() );\n    }\n\n    std::pair< bluetoe::details::ecdh_public_key_t, bluetoe::details::ecdh_private_key_t > security_tool_box::generate_keys()\n    {\n        uECC_set_rng( []( uint8_t *dest, unsigned size )->int {\n            std::generate( dest, dest + size, random_number8 );\n\n            return 1;\n        } );\n\n        bluetoe::details::ecdh_public_key_t  public_key;\n        bluetoe::details::ecdh_private_key_t private_key;\n\n        const auto rc = uECC_make_key( public_key.data(), private_key.data() );\n        static_cast< void >( rc );\n        assert( rc == 1 );\n\n        std::reverse( public_key.begin(), public_key.begin() + 32 );\n        std::reverse( public_key.begin() + 32, public_key.end() );\n        std::reverse( private_key.begin(), private_key.end() );\n\n        return { public_key, private_key };\n    }\n\n    bluetoe::details::uint128_t security_tool_box::select_random_nonce()\n    {\n        bluetoe::details::uint128_t result;\n        std::generate( result.begin(), result.end(), random_number8 );\n\n        return result;\n    }\n\n    bluetoe::details::ecdh_shared_secret_t security_tool_box::p256( const std::uint8_t* private_key, const std::uint8_t* public_key )\n    {\n        bluetoe::details::ecdh_private_key_t shared_secret;\n        bluetoe::details::ecdh_private_key_t priv_key;\n        bluetoe::details::ecdh_public_key_t  pub_key;\n        std::reverse_copy( public_key, public_key + 32, pub_key.begin() );\n        std::reverse_copy( public_key + 32, public_key + 64, pub_key.begin() + 32 );\n        std::reverse_copy( private_key, private_key + 32, priv_key.begin() );\n\n        const int rc = uECC_shared_secret( pub_key.data(), priv_key.data(), shared_secret.data() );\n        static_cast< void >( rc );\n        assert( rc == 1 );\n\n        bluetoe::details::ecdh_shared_secret_t result;\n        static_assert(shared_secret.size() == result.size(), \"\");\n\n        std::reverse_copy( shared_secret.begin(), shared_secret.end(), result.begin() );\n\n        return result;\n    }\n\n    static bluetoe::details::uint128_t left_shift(const bluetoe::details::uint128_t& input)\n    {\n        bluetoe::details::uint128_t output;\n\n        assert(input.size() == output.size());\n\n        std::uint8_t overflow = 0;\n        for ( std::size_t i = 0; i != input.size(); ++i )\n        {\n            output[ i ] = ( input[i] << 1 ) | overflow;\n            overflow = ( input[ i ] & 0x80 ) ? 1 : 0;\n        }\n\n        return output;\n    }\n\n    static bluetoe::details::uint128_t aes_cmac_k1_subkey_generation( const bluetoe::details::uint128_t& key )\n    {\n        const bluetoe::details::uint128_t zero = {{ 0x00 }};\n        const bluetoe::details::uint128_t C    = {{ 0x87 }};\n\n        const bluetoe::details::uint128_t k0 = aes_le( key, zero );\n\n        const bluetoe::details::uint128_t k1 = ( k0.back() & 0x80 ) == 0\n            ? left_shift(k0)\n            : xor_( left_shift(k0), C );\n\n        return k1;\n    }\n\n    static bluetoe::details::uint128_t aes_cmac_k2_subkey_generation( const bluetoe::details::uint128_t& key )\n    {\n        const bluetoe::details::uint128_t C    = {{ 0x87 }};\n\n        const bluetoe::details::uint128_t k1 = aes_cmac_k1_subkey_generation( key );\n        const bluetoe::details::uint128_t k2 = ( k1.back() & 0x80 ) == 0\n            ? left_shift(k1)\n            : xor_( left_shift(k1), C );\n\n        return k2;\n    }\n\n    bluetoe::details::uint128_t security_tool_box::f4( const std::uint8_t* u, const std::uint8_t* v, const std::array< std::uint8_t, 16 >& k, std::uint8_t z )\n    {\n        const bluetoe::details::uint128_t m4 = {{\n            0x00, 0x00, 0x00, 0x00,\n            0x00, 0x00, 0x00, 0x00,\n            0x00, 0x00, 0x00, 0x00,\n            0x00, 0x00, 0x80, z\n        }};\n\n        auto t0 = aes_le( k, &u[16] );\n        auto t1 = aes_le( k, xor_( t0, &u[0] ) );\n        auto t2 = aes_le( k, xor_( t1, &v[16] ) );\n        auto t3 = aes_le( k, xor_( t2, &v[0] ) );\n\n        return aes_le( k, xor_( t3, xor_( aes_cmac_k2_subkey_generation( k ), m4 ) ) );\n    }\n\n    static bluetoe::details::uint128_t f5_cmac(\n        const bluetoe::details::uint128_t& key,\n        const std::uint8_t* buffer )\n    {\n        const std::uint8_t* m0 = &buffer[ 48 ];\n        const std::uint8_t* m1 = &buffer[ 32 ];\n        const std::uint8_t* m2 = &buffer[ 16 ];\n        const std::uint8_t* m3 = &buffer[ 0 ];\n\n        auto t0 = aes_le( key, m0 );\n        auto t1 = aes_le( key, xor_( t0, m1 ) );\n        auto t2 = aes_le( key, xor_( t1, m2 ) );\n\n        return aes_le( key, xor_( t2, xor_( aes_cmac_k2_subkey_generation( key ), m3 ) ) );\n    }\n\n    static bluetoe::details::uint128_t f5_key( const bluetoe::details::ecdh_shared_secret_t dh_key )\n    {\n        static const bluetoe::details::uint128_t salt = {{\n            0xBE, 0x83, 0x60, 0x5A, 0xDB, 0x0B, 0x37, 0x60,\n            0x38, 0xA5, 0xF5, 0xAA, 0x91, 0x83, 0x88, 0x6C\n        }};\n\n        auto t0 = aes_le( salt, &dh_key[ 16 ] );\n\n        return aes_le( salt, xor_( t0, xor_( aes_cmac_k1_subkey_generation( salt ), &dh_key[ 0 ] ) ) );\n    }\n\n    std::pair< bluetoe::details::uint128_t, bluetoe::details::uint128_t > security_tool_box::f5(\n        const bluetoe::details::ecdh_shared_secret_t dh_key,\n        const bluetoe::details::uint128_t& nonce_central,\n        const bluetoe::details::uint128_t& nonce_periperal,\n        const bluetoe::link_layer::device_address& addr_controller,\n        const bluetoe::link_layer::device_address& addr_peripheral )\n    {\n        // all 4 blocks are allocated in revers order to make it easier to copy data that overlaps\n        // two blocks\n        std::uint8_t buffer[ 64 ] = { 0 };\n\n        static const std::uint8_t m0_fill[] = {\n            0x65, 0x6c, 0x74, 0x62\n        };\n\n        static const std::uint8_t m3_fill[] = {\n            0x80, 0x00, 0x01\n        };\n\n        std::copy( std::begin( m0_fill ), std::end( m0_fill ), &buffer[ 11 + 48 ] );\n        std::copy( std::begin( m3_fill ), std::end( m3_fill ), &buffer[ 10 ] );\n\n        std::copy( nonce_central.begin(), nonce_central.end(), &buffer[ 32 + 11 ] );\n        std::copy( nonce_periperal.begin(), nonce_periperal.end(), &buffer[ 16 + 11 ] );\n\n        buffer[ 16 + 10 ] = addr_controller.is_random() ? 1 : 0;\n        std::copy( addr_controller.begin(), addr_controller.end(), &buffer[ 16 + 4 ] );\n        buffer[ 16 + 3 ] = addr_peripheral.is_random() ? 1 : 0;\n        std::copy( addr_peripheral.begin(), addr_peripheral.end(), &buffer[ 13 ] );\n\n        const bluetoe::details::uint128_t key     = f5_key( dh_key );\n        const bluetoe::details::uint128_t mac_key = f5_cmac( key, buffer );\n        // increment counter\n        buffer[ 15 + 48 ] = 1;\n        const bluetoe::details::uint128_t ltk     = f5_cmac( key, buffer );\n\n        return { mac_key, ltk };\n    }\n\n    bluetoe::details::uint128_t security_tool_box::f6(\n        const bluetoe::details::uint128_t& key,\n        const bluetoe::details::uint128_t& n1,\n        const bluetoe::details::uint128_t& n2,\n        const bluetoe::details::uint128_t& r,\n        const bluetoe::details::io_capabilities_t& io_caps,\n        const bluetoe::link_layer::device_address& addr_controller,\n        const bluetoe::link_layer::device_address& addr_peripheral )\n    {\n        std::uint8_t m4_m3[ 32 ] = { 0 };\n\n        std::copy( io_caps.begin(), io_caps.end(), &m4_m3[ 16 + 13 ] );\n        m4_m3[ 16 + 12 ] = addr_controller.is_random() ? 1 : 0;\n        std::copy( addr_controller.begin(), addr_controller.end(), &m4_m3[ 22 ] );\n        m4_m3[ 16 + 5 ] = addr_peripheral.is_random() ? 1 : 0;\n        std::copy( addr_peripheral.begin(), addr_peripheral.end(), &m4_m3[ 15 ] );\n        m4_m3[ 14 ] = 0x80;\n\n        const std::uint8_t* m3 = &m4_m3[ 16 ];\n        const std::uint8_t* m4 = &m4_m3[ 0 ];\n\n        auto t0 = aes_le( key, n1 );\n        auto t1 = aes_le( key, xor_( t0, n2 ) );\n        auto t2 = aes_le( key, xor_( t1, r ) );\n        auto t3 = aes_le( key, xor_( t2, m3 ) );\n\n        return aes_le( key, xor_( t3, xor_( aes_cmac_k2_subkey_generation( key ), m4 ) ) );\n    }\n\n    std::uint32_t security_tool_box::g2(\n        const std::uint8_t*                 u,\n        const std::uint8_t*                 v,\n        const bluetoe::details::uint128_t&  x,\n        const bluetoe::details::uint128_t&  y )\n    {\n        auto t0 = aes_le( x, u + 16 );\n        auto t1 = aes_le( x, xor_( t0, u ) );\n        auto t2 = aes_le( x, xor_( t1, v + 16 ) );\n        auto t3 = aes_le( x, xor_( t2, v ) );\n        auto t4 = aes_le( x, xor_( t3, xor_( aes_cmac_k1_subkey_generation( x ), y ) ) );\n\n        return bluetoe::details::read_32bit( t4.begin() );\n    }\n\n    bluetoe::details::uint128_t security_tool_box::create_passkey()\n    {\n        const bluetoe::details::uint128_t result{{\n            random_number8(), random_number8(), random_number8()\n        }};\n\n        return result;\n    }\n\n}\n}\n"
  },
  {
    "path": "bluetoe/bindings/nordic/uECC/CMakeLists.txt",
    "content": "add_library(bluetoe_bindings_uECC STATIC\n            uECC.c)\n\nadd_library(bluetoe::bindings::nrf::uecc ALIAS bluetoe_bindings_uECC)\n\ntarget_include_directories(bluetoe_bindings_uECC PUBLIC ${CMAKE_CURRENT_LIST_DIR})\ntarget_compile_definitions(bluetoe_bindings_uECC PRIVATE uECC_CURVE=uECC_secp256r1 uECC_ASM=1)\nset_source_files_properties(uECC.c PROPERTIES COMPILE_OPTIONS -Wno-unused-parameter)\n\n"
  },
  {
    "path": "bluetoe/bindings/nordic/uECC/asm_arm.inc",
    "content": "#define DEC_5 4\n#define DEC_6 5\n#define DEC_7 6\n#define DEC_8 7\n\n#define DEC(N) uECC_CONCAT(DEC_, N)\n\n#define REPEAT_1(stuff) stuff\n#define REPEAT_2(stuff) REPEAT_1(stuff) stuff\n#define REPEAT_3(stuff) REPEAT_2(stuff) stuff\n#define REPEAT_4(stuff) REPEAT_3(stuff) stuff\n#define REPEAT_5(stuff) REPEAT_4(stuff) stuff\n#define REPEAT_6(stuff) REPEAT_5(stuff) stuff\n#define REPEAT_7(stuff) REPEAT_6(stuff) stuff\n#define REPEAT_8(stuff) REPEAT_7(stuff) stuff\n\n#define REPEAT(N, stuff) uECC_CONCAT(REPEAT_, N)(stuff)\n\n#define STR2(thing) #thing\n#define STR(thing) STR2(thing)\n\n#if (uECC_ASM == uECC_asm_fast)\n\nstatic uint32_t vli_add(uint32_t *result, const uint32_t *left, const uint32_t *right) {\n    uint32_t carry = 0;\n    uint32_t left_word;\n    uint32_t right_word;\n\n    __asm__ volatile (\n        \".syntax unified \\n\\t\"\n        \"ldmia %[lptr]!, {%[left]} \\n\\t\"  /* Load left word. */\n        \"ldmia %[rptr]!, {%[right]} \\n\\t\" /* Load right word. */\n        \"adds %[left], %[right] \\n\\t\"     /* Add first word. */\n        \"stmia %[dptr]!, {%[left]} \\n\\t\"  /* Store result word. */\n\n        /* Now we just do the remaining words with the carry bit (using ADC) */\n        REPEAT(DEC(uECC_WORDS),\n            \"ldmia %[lptr]!, {%[left]} \\n\\t\"\n            \"ldmia %[rptr]!, {%[right]} \\n\\t\"\n            \"adcs %[left], %[right] \\n\\t\"\n            \"stmia %[dptr]!, {%[left]} \\n\\t\")\n\n        \"adcs %[carry], %[carry] \\n\\t\" /* Store carry bit. */\n    #if (uECC_PLATFORM != uECC_arm_thumb2)\n        \".syntax divided \\n\\t\"\n    #endif\n    #if (uECC_PLATFORM == uECC_arm_thumb)\n        : [dptr] \"+l\" (result), [lptr] \"+l\" (left), [rptr] \"+l\" (right),\n          [carry] \"+l\" (carry), [left] \"=l\" (left_word), [right] \"=l\" (right_word)\n    #else\n        : [dptr] \"+r\" (result), [lptr] \"+r\" (left), [rptr] \"+r\" (right),\n          [carry] \"+r\" (carry), [left] \"=r\" (left_word), [right] \"=r\" (right_word)\n    #endif\n        :\n        : \"cc\", \"memory\"\n    );\n    return carry;\n}\n#define asm_add 1\n\nstatic uint32_t vli_sub(uint32_t *result, const uint32_t *left, const uint32_t *right) {\n    uint32_t carry = 0;\n    uint32_t left_word;\n    uint32_t right_word;\n\n    __asm__ volatile (\n        \".syntax unified \\n\\t\"\n        \"ldmia %[lptr]!, {%[left]} \\n\\t\"  /* Load left word. */\n        \"ldmia %[rptr]!, {%[right]} \\n\\t\" /* Load right word. */\n        \"subs %[left], %[right] \\n\\t\"     /* Subtract. */\n        \"stmia %[dptr]!, {%[left]} \\n\\t\"  /* Store result word. */\n\n        /* Now we just do the remaining words with the carry bit (using SBC) */\n        REPEAT(DEC(uECC_WORDS),\n            \"ldmia %[lptr]!, {%[left]} \\n\\t\"\n            \"ldmia %[rptr]!, {%[right]} \\n\\t\"\n            \"sbcs %[left], %[right] \\n\\t\"\n            \"stmia %[dptr]!, {%[left]} \\n\\t\")\n\n        \"adcs %[carry], %[carry] \\n\\t\" /* Store carry bit. */\n    #if (uECC_PLATFORM != uECC_arm_thumb2)\n        \".syntax divided \\n\\t\"\n    #endif\n    #if (uECC_PLATFORM == uECC_arm_thumb)\n        : [dptr] \"+l\" (result), [lptr] \"+l\" (left), [rptr] \"+l\" (right),\n          [carry] \"+l\" (carry), [left] \"=l\" (left_word), [right] \"=l\" (right_word)\n    #else\n        : [dptr] \"+r\" (result), [lptr] \"+r\" (left), [rptr] \"+r\" (right),\n          [carry] \"+r\" (carry), [left] \"=r\" (left_word), [right] \"=r\" (right_word)\n    #endif\n        :\n        : \"cc\", \"memory\"\n    );\n    return !carry; // note that on ARM, carry flag set means \"no borrow\" when subtracting\n                   // (for some reason...)\n}\n#define asm_sub 1\n\n#if (uECC_PLATFORM != uECC_arm_thumb)\n#if (uECC_WORDS == 5)\nstatic void vli_mult(uint32_t *result, const uint32_t *left, const uint32_t *right) {\n    register uint32_t *r0 __asm__(\"r0\") = result;\n    register const uint32_t *r1 __asm__(\"r1\") = left;\n    register const uint32_t *r2 __asm__(\"r2\") = right;\n\n    __asm__ volatile (\n        \".syntax unified \\n\\t\"\n        \"add r0, 12 \\n\\t\"\n        \"add r2, 12 \\n\\t\"\n        \"ldmia r1!, {r3,r4} \\n\\t\"\n        \"ldmia r2!, {r6,r7} \\n\\t\"\n\n        \"umull r11, r12, r3, r6 \\n\\t\"\n        \"stmia r0!, {r11} \\n\\t\"\n\n        \"mov r10, #0 \\n\\t\"\n        \"umull r11, r9, r3, r7 \\n\\t\"\n        \"adds r12, r11 \\n\\t\"\n        \"adc r9, #0 \\n\\t\"\n        \"umull r11, r14, r4, r6 \\n\\t\"\n        \"adds r12, r11 \\n\\t\"\n        \"adcs r9, r14 \\n\\t\"\n        \"adc r10, #0 \\n\\t\"\n        \"stmia r0!, {r12} \\n\\t\"\n\n        \"umull r12, r14, r4, r7 \\n\\t\"\n        \"adds r9, r12 \\n\\t\"\n        \"adc r10, r14 \\n\\t\"\n        \"stmia r0!, {r9, r10} \\n\\t\"\n\n        \"sub r0, 28 \\n\\t\"\n        \"sub r2, 20 \\n\\t\"\n        \"ldmia r2!, {r6,r7,r8} \\n\\t\"\n        \"ldmia r1!, {r5} \\n\\t\"\n\n        \"umull r11, r12, r3, r6 \\n\\t\"\n        \"stmia r0!, {r11} \\n\\t\"\n\n        \"mov r10, #0 \\n\\t\"\n        \"umull r11, r9, r3, r7 \\n\\t\"\n        \"adds r12, r11 \\n\\t\"\n        \"adc r9, #0 \\n\\t\"\n        \"umull r11, r14, r4, r6 \\n\\t\"\n        \"adds r12, r11 \\n\\t\"\n        \"adcs r9, r14 \\n\\t\"\n        \"adc r10, #0 \\n\\t\"\n        \"stmia r0!, {r12} \\n\\t\"\n\n        \"mov r11, #0 \\n\\t\"\n        \"umull r12, r14, r3, r8 \\n\\t\"\n        \"adds r9, r12 \\n\\t\"\n        \"adcs r10, r14 \\n\\t\"\n        \"adc r11, #0 \\n\\t\"\n        \"umull r12, r14, r4, r7 \\n\\t\"\n        \"adds r9, r12 \\n\\t\"\n        \"adcs r10, r14 \\n\\t\"\n        \"adc r11, #0 \\n\\t\"\n        \"umull r12, r14, r5, r6 \\n\\t\"\n        \"adds r9, r12 \\n\\t\"\n        \"adcs r10, r14 \\n\\t\"\n        \"adc r11, #0 \\n\\t\"\n        \"stmia r0!, {r9} \\n\\t\"\n\n        \"ldmia r1!, {r3} \\n\\t\"\n        \"mov r12, #0 \\n\\t\"\n        \"umull r14, r9, r4, r8 \\n\\t\"\n        \"adds r10, r14 \\n\\t\"\n        \"adcs r11, r9 \\n\\t\"\n        \"adc r12, #0 \\n\\t\"\n        \"umull r14, r9, r5, r7 \\n\\t\"\n        \"adds r10, r14 \\n\\t\"\n        \"adcs r11, r9 \\n\\t\"\n        \"adc r12, #0 \\n\\t\"\n        \"umull r14, r9, r3, r6 \\n\\t\"\n        \"adds r10, r14 \\n\\t\"\n        \"adcs r11, r9 \\n\\t\"\n        \"adc r12, #0 \\n\\t\"\n        \"ldr r14, [r0] \\n\\t\"\n        \"adds r10, r14 \\n\\t\"\n        \"adcs r11, #0 \\n\\t\"\n        \"adc r12, #0 \\n\\t\"\n        \"stmia r0!, {r10} \\n\\t\"\n\n        \"ldmia r1!, {r4} \\n\\t\"\n        \"mov r14, #0 \\n\\t\"\n        \"umull r9, r10, r5, r8 \\n\\t\"\n        \"adds r11, r9 \\n\\t\"\n        \"adcs r12, r10 \\n\\t\"\n        \"adc r14, #0 \\n\\t\"\n        \"umull r9, r10, r3, r7 \\n\\t\"\n        \"adds r11, r9 \\n\\t\"\n        \"adcs r12, r10 \\n\\t\"\n        \"adc r14, #0 \\n\\t\"\n        \"umull r9, r10, r4, r6 \\n\\t\"\n        \"adds r11, r9 \\n\\t\"\n        \"adcs r12, r10 \\n\\t\"\n        \"adc r14, #0 \\n\\t\"\n        \"ldr r9, [r0] \\n\\t\"\n        \"adds r11, r9 \\n\\t\"\n        \"adcs r12, #0 \\n\\t\"\n        \"adc r14, #0 \\n\\t\"\n        \"stmia r0!, {r11} \\n\\t\"\n\n        \"ldmia r2!, {r6} \\n\\t\"\n        \"mov r9, #0 \\n\\t\"\n        \"umull r10, r11, r5, r6 \\n\\t\"\n        \"adds r12, r10 \\n\\t\"\n        \"adcs r14, r11 \\n\\t\"\n        \"adc r9, #0 \\n\\t\"\n        \"umull r10, r11, r3, r8 \\n\\t\"\n        \"adds r12, r10 \\n\\t\"\n        \"adcs r14, r11 \\n\\t\"\n        \"adc r9, #0 \\n\\t\"\n        \"umull r10, r11, r4, r7 \\n\\t\"\n        \"adds r12, r10 \\n\\t\"\n        \"adcs r14, r11 \\n\\t\"\n        \"adc r9, #0 \\n\\t\"\n        \"ldr r10, [r0] \\n\\t\"\n        \"adds r12, r10 \\n\\t\"\n        \"adcs r14, #0 \\n\\t\"\n        \"adc r9, #0 \\n\\t\"\n        \"stmia r0!, {r12} \\n\\t\"\n\n        \"ldmia r2!, {r7} \\n\\t\"\n        \"mov r10, #0 \\n\\t\"\n        \"umull r11, r12, r5, r7 \\n\\t\"\n        \"adds r14, r11 \\n\\t\"\n        \"adcs r9, r12 \\n\\t\"\n        \"adc r10, #0 \\n\\t\"\n        \"umull r11, r12, r3, r6 \\n\\t\"\n        \"adds r14, r11 \\n\\t\"\n        \"adcs r9, r12 \\n\\t\"\n        \"adc r10, #0 \\n\\t\"\n        \"umull r11, r12, r4, r8 \\n\\t\"\n        \"adds r14, r11 \\n\\t\"\n        \"adcs r9, r12 \\n\\t\"\n        \"adc r10, #0 \\n\\t\"\n        \"ldr r11, [r0] \\n\\t\"\n        \"adds r14, r11 \\n\\t\"\n        \"adcs r9, #0 \\n\\t\"\n        \"adc r10, #0 \\n\\t\"\n        \"stmia r0!, {r14} \\n\\t\"\n\n        \"mov r11, #0 \\n\\t\"\n        \"umull r12, r14, r3, r7 \\n\\t\"\n        \"adds r9, r12 \\n\\t\"\n        \"adcs r10, r14 \\n\\t\"\n        \"adc r11, #0 \\n\\t\"\n        \"umull r12, r14, r4, r6 \\n\\t\"\n        \"adds r9, r12 \\n\\t\"\n        \"adcs r10, r14 \\n\\t\"\n        \"adc r11, #0 \\n\\t\"\n        \"stmia r0!, {r9} \\n\\t\"\n\n        \"umull r14, r9, r4, r7 \\n\\t\"\n        \"adds r10, r14 \\n\\t\"\n        \"adc r11, r9 \\n\\t\"\n        \"stmia r0!, {r10, r11} \\n\\t\"\n    #if (uECC_PLATFORM != uECC_arm_thumb2)\n        \".syntax divided \\n\\t\"\n    #endif\n        : \"+r\" (r0), \"+r\" (r1), \"+r\" (r2)\n        :\n        : \"r3\", \"r4\", \"r5\", \"r6\", \"r7\", \"r8\", \"r9\", \"r10\", \"r11\", \"r12\", \"r14\", \"cc\", \"memory\"\n    );\n}\n#define asm_mult 1\n#endif /* (uECC_WORDS == 5) */\n\n#if (uECC_WORDS == 6)\nstatic void vli_mult(uint32_t *result, const uint32_t *left, const uint32_t *right) {\n    register uint32_t *r0 __asm__(\"r0\") = result;\n    register const uint32_t *r1 __asm__(\"r1\") = left;\n    register const uint32_t *r2 __asm__(\"r2\") = right;\n\n    __asm__ volatile (\n        \".syntax unified \\n\\t\"\n        \"add r0, 12 \\n\\t\"\n        \"add r2, 12 \\n\\t\"\n        \"ldmia r1!, {r3,r4,r5} \\n\\t\"\n        \"ldmia r2!, {r6,r7,r8} \\n\\t\"\n\n        \"umull r11, r12, r3, r6 \\n\\t\"\n        \"stmia r0!, {r11} \\n\\t\"\n\n        \"mov r10, #0 \\n\\t\"\n        \"umull r11, r9, r3, r7 \\n\\t\"\n        \"adds r12, r11 \\n\\t\"\n        \"adc r9, #0 \\n\\t\"\n        \"umull r11, r14, r4, r6 \\n\\t\"\n        \"adds r12, r11 \\n\\t\"\n        \"adcs r9, r14 \\n\\t\"\n        \"adc r10, #0 \\n\\t\"\n        \"stmia r0!, {r12} \\n\\t\"\n\n        \"mov r11, #0 \\n\\t\"\n        \"umull r12, r14, r3, r8 \\n\\t\"\n        \"adds r9, r12 \\n\\t\"\n        \"adcs r10, r14 \\n\\t\"\n        \"adc r11, #0 \\n\\t\"\n        \"umull r12, r14, r4, r7 \\n\\t\"\n        \"adds r9, r12 \\n\\t\"\n        \"adcs r10, r14 \\n\\t\"\n        \"adc r11, #0 \\n\\t\"\n        \"umull r12, r14, r5, r6 \\n\\t\"\n        \"adds r9, r12 \\n\\t\"\n        \"adcs r10, r14 \\n\\t\"\n        \"adc r11, #0 \\n\\t\"\n        \"stmia r0!, {r9} \\n\\t\"\n\n        \"mov r12, #0 \\n\\t\"\n        \"umull r14, r9, r4, r8 \\n\\t\"\n        \"adds r10, r14 \\n\\t\"\n        \"adcs r11, r9 \\n\\t\"\n        \"adc r12, #0 \\n\\t\"\n        \"umull r14, r9, r5, r7 \\n\\t\"\n        \"adds r10, r14 \\n\\t\"\n        \"adcs r11, r9 \\n\\t\"\n        \"adc r12, #0 \\n\\t\"\n        \"stmia r0!, {r10} \\n\\t\"\n\n        \"umull r9, r10, r5, r8 \\n\\t\"\n        \"adds r11, r9 \\n\\t\"\n        \"adc r12, r10 \\n\\t\"\n        \"stmia r0!, {r11, r12} \\n\\t\"\n\n        \"sub r0, 36 \\n\\t\"\n        \"sub r2, 24 \\n\\t\"\n        \"ldmia r2!, {r6,r7,r8} \\n\\t\"\n\n        \"umull r11, r12, r3, r6 \\n\\t\"\n        \"stmia r0!, {r11} \\n\\t\"\n\n        \"mov r10, #0 \\n\\t\"\n        \"umull r11, r9, r3, r7 \\n\\t\"\n        \"adds r12, r11 \\n\\t\"\n        \"adc r9, #0 \\n\\t\"\n        \"umull r11, r14, r4, r6 \\n\\t\"\n        \"adds r12, r11 \\n\\t\"\n        \"adcs r9, r14 \\n\\t\"\n        \"adc r10, #0 \\n\\t\"\n        \"stmia r0!, {r12} \\n\\t\"\n\n        \"mov r11, #0 \\n\\t\"\n        \"umull r12, r14, r3, r8 \\n\\t\"\n        \"adds r9, r12 \\n\\t\"\n        \"adcs r10, r14 \\n\\t\"\n        \"adc r11, #0 \\n\\t\"\n        \"umull r12, r14, r4, r7 \\n\\t\"\n        \"adds r9, r12 \\n\\t\"\n        \"adcs r10, r14 \\n\\t\"\n        \"adc r11, #0 \\n\\t\"\n        \"umull r12, r14, r5, r6 \\n\\t\"\n        \"adds r9, r12 \\n\\t\"\n        \"adcs r10, r14 \\n\\t\"\n        \"adc r11, #0 \\n\\t\"\n        \"stmia r0!, {r9} \\n\\t\"\n\n        \"ldmia r1!, {r3} \\n\\t\"\n        \"mov r12, #0 \\n\\t\"\n        \"umull r14, r9, r4, r8 \\n\\t\"\n        \"adds r10, r14 \\n\\t\"\n        \"adcs r11, r9 \\n\\t\"\n        \"adc r12, #0 \\n\\t\"\n        \"umull r14, r9, r5, r7 \\n\\t\"\n        \"adds r10, r14 \\n\\t\"\n        \"adcs r11, r9 \\n\\t\"\n        \"adc r12, #0 \\n\\t\"\n        \"umull r14, r9, r3, r6 \\n\\t\"\n        \"adds r10, r14 \\n\\t\"\n        \"adcs r11, r9 \\n\\t\"\n        \"adc r12, #0 \\n\\t\"\n        \"ldr r14, [r0] \\n\\t\"\n        \"adds r10, r14 \\n\\t\"\n        \"adcs r11, #0 \\n\\t\"\n        \"adc r12, #0 \\n\\t\"\n        \"stmia r0!, {r10} \\n\\t\"\n\n        \"ldmia r1!, {r4} \\n\\t\"\n        \"mov r14, #0 \\n\\t\"\n        \"umull r9, r10, r5, r8 \\n\\t\"\n        \"adds r11, r9 \\n\\t\"\n        \"adcs r12, r10 \\n\\t\"\n        \"adc r14, #0 \\n\\t\"\n        \"umull r9, r10, r3, r7 \\n\\t\"\n        \"adds r11, r9 \\n\\t\"\n        \"adcs r12, r10 \\n\\t\"\n        \"adc r14, #0 \\n\\t\"\n        \"umull r9, r10, r4, r6 \\n\\t\"\n        \"adds r11, r9 \\n\\t\"\n        \"adcs r12, r10 \\n\\t\"\n        \"adc r14, #0 \\n\\t\"\n        \"ldr r9, [r0] \\n\\t\"\n        \"adds r11, r9 \\n\\t\"\n        \"adcs r12, #0 \\n\\t\"\n        \"adc r14, #0 \\n\\t\"\n        \"stmia r0!, {r11} \\n\\t\"\n\n        \"ldmia r1!, {r5} \\n\\t\"\n        \"mov r9, #0 \\n\\t\"\n        \"umull r10, r11, r3, r8 \\n\\t\"\n        \"adds r12, r10 \\n\\t\"\n        \"adcs r14, r11 \\n\\t\"\n        \"adc r9, #0 \\n\\t\"\n        \"umull r10, r11, r4, r7 \\n\\t\"\n        \"adds r12, r10 \\n\\t\"\n        \"adcs r14, r11 \\n\\t\"\n        \"adc r9, #0 \\n\\t\"\n        \"umull r10, r11, r5, r6 \\n\\t\"\n        \"adds r12, r10 \\n\\t\"\n        \"adcs r14, r11 \\n\\t\"\n        \"adc r9, #0 \\n\\t\"\n        \"ldr r10, [r0] \\n\\t\"\n        \"adds r12, r10 \\n\\t\"\n        \"adcs r14, #0 \\n\\t\"\n        \"adc r9, #0 \\n\\t\"\n        \"stmia r0!, {r12} \\n\\t\"\n\n        \"ldmia r2!, {r6} \\n\\t\"\n        \"mov r10, #0 \\n\\t\"\n        \"umull r11, r12, r3, r6 \\n\\t\"\n        \"adds r14, r11 \\n\\t\"\n        \"adcs r9, r12 \\n\\t\"\n        \"adc r10, #0 \\n\\t\"\n        \"umull r11, r12, r4, r8 \\n\\t\"\n        \"adds r14, r11 \\n\\t\"\n        \"adcs r9, r12 \\n\\t\"\n        \"adc r10, #0 \\n\\t\"\n        \"umull r11, r12, r5, r7 \\n\\t\"\n        \"adds r14, r11 \\n\\t\"\n        \"adcs r9, r12 \\n\\t\"\n        \"adc r10, #0 \\n\\t\"\n        \"ldr r11, [r0] \\n\\t\"\n        \"adds r14, r11 \\n\\t\"\n        \"adcs r9, #0 \\n\\t\"\n        \"adc r10, #0 \\n\\t\"\n        \"stmia r0!, {r14} \\n\\t\"\n\n        \"ldmia r2!, {r7} \\n\\t\"\n        \"mov r11, #0 \\n\\t\"\n        \"umull r12, r14, r3, r7 \\n\\t\"\n        \"adds r9, r12 \\n\\t\"\n        \"adcs r10, r14 \\n\\t\"\n        \"adc r11, #0 \\n\\t\"\n        \"umull r12, r14, r4, r6 \\n\\t\"\n        \"adds r9, r12 \\n\\t\"\n        \"adcs r10, r14 \\n\\t\"\n        \"adc r11, #0 \\n\\t\"\n        \"umull r12, r14, r5, r8 \\n\\t\"\n        \"adds r9, r12 \\n\\t\"\n        \"adcs r10, r14 \\n\\t\"\n        \"adc r11, #0 \\n\\t\"\n        \"ldr r12, [r0] \\n\\t\"\n        \"adds r9, r12 \\n\\t\"\n        \"adcs r10, #0 \\n\\t\"\n        \"adc r11, #0 \\n\\t\"\n        \"stmia r0!, {r9} \\n\\t\"\n\n        \"ldmia r2!, {r8} \\n\\t\"\n        \"mov r12, #0 \\n\\t\"\n        \"umull r14, r9, r3, r8 \\n\\t\"\n        \"adds r10, r14 \\n\\t\"\n        \"adcs r11, r9 \\n\\t\"\n        \"adc r12, #0 \\n\\t\"\n        \"umull r14, r9, r4, r7 \\n\\t\"\n        \"adds r10, r14 \\n\\t\"\n        \"adcs r11, r9 \\n\\t\"\n        \"adc r12, #0 \\n\\t\"\n        \"umull r14, r9, r5, r6 \\n\\t\"\n        \"adds r10, r14 \\n\\t\"\n        \"adcs r11, r9 \\n\\t\"\n        \"adc r12, #0 \\n\\t\"\n        \"ldr r14, [r0] \\n\\t\"\n        \"adds r10, r14 \\n\\t\"\n        \"adcs r11, #0 \\n\\t\"\n        \"adc r12, #0 \\n\\t\"\n        \"stmia r0!, {r10} \\n\\t\"\n\n        \"mov r14, #0 \\n\\t\"\n        \"umull r9, r10, r4, r8 \\n\\t\"\n        \"adds r11, r9 \\n\\t\"\n        \"adcs r12, r10 \\n\\t\"\n        \"adc r14, #0 \\n\\t\"\n        \"umull r9, r10, r5, r7 \\n\\t\"\n        \"adds r11, r9 \\n\\t\"\n        \"adcs r12, r10 \\n\\t\"\n        \"adc r14, #0 \\n\\t\"\n        \"stmia r0!, {r11} \\n\\t\"\n\n        \"umull r10, r11, r5, r8 \\n\\t\"\n        \"adds r12, r10 \\n\\t\"\n        \"adc r14, r11 \\n\\t\"\n        \"stmia r0!, {r12, r14} \\n\\t\"\n    #if (uECC_PLATFORM != uECC_arm_thumb2)\n        \".syntax divided \\n\\t\"\n    #endif\n        : \"+r\" (r0), \"+r\" (r1), \"+r\" (r2)\n        :\n        : \"r3\", \"r4\", \"r5\", \"r6\", \"r7\", \"r8\", \"r9\", \"r10\", \"r11\", \"r12\", \"r14\", \"cc\", \"memory\"\n    );\n}\n#define asm_mult 1\n#endif /* (uECC_WORDS == 6) */\n\n#if (uECC_WORDS == 7)\nstatic void vli_mult(uint32_t *result, const uint32_t *left, const uint32_t *right) {\n    register uint32_t *r0 __asm__(\"r0\") = result;\n    register const uint32_t *r1 __asm__(\"r1\") = left;\n    register const uint32_t *r2 __asm__(\"r2\") = right;\n\n    __asm__ volatile (\n        \".syntax unified \\n\\t\"\n        \"add r0, 24 \\n\\t\"\n        \"add r2, 24 \\n\\t\"\n        \"ldmia r1!, {r3} \\n\\t\"\n        \"ldmia r2!, {r6} \\n\\t\"\n\n        \"umull r9, r10, r3, r6 \\n\\t\"\n        \"stmia r0!, {r9, r10} \\n\\t\"\n\n        \"sub r0, 20 \\n\\t\"\n        \"sub r2, 16 \\n\\t\"\n        \"ldmia r2!, {r6, r7, r8} \\n\\t\"\n        \"ldmia r1!, {r4, r5} \\n\\t\"\n\n        \"umull r9, r10, r3, r6 \\n\\t\"\n        \"stmia r0!, {r9} \\n\\t\"\n\n        \"mov r14, #0 \\n\\t\"\n        \"umull r9, r12, r3, r7 \\n\\t\"\n        \"adds r10, r9 \\n\\t\"\n        \"adc r12, #0 \\n\\t\"\n        \"umull r9, r11, r4, r6 \\n\\t\"\n        \"adds r10, r9 \\n\\t\"\n        \"adcs r12, r11 \\n\\t\"\n        \"adc r14, #0 \\n\\t\"\n        \"stmia r0!, {r10} \\n\\t\"\n\n        \"mov r9, #0 \\n\\t\"\n        \"umull r10, r11, r3, r8 \\n\\t\"\n        \"adds r12, r10 \\n\\t\"\n        \"adcs r14, r11 \\n\\t\"\n        \"adc r9, #0 \\n\\t\"\n        \"umull r10, r11, r4, r7 \\n\\t\"\n        \"adds r12, r10 \\n\\t\"\n        \"adcs r14, r11 \\n\\t\"\n        \"adc r9, #0 \\n\\t\"\n        \"umull r10, r11, r5, r6 \\n\\t\"\n        \"adds r12, r10 \\n\\t\"\n        \"adcs r14, r11 \\n\\t\"\n        \"adc r9, #0 \\n\\t\"\n        \"stmia r0!, {r12} \\n\\t\"\n\n        \"ldmia r1!, {r3} \\n\\t\"\n        \"mov r10, #0 \\n\\t\"\n        \"umull r11, r12, r4, r8 \\n\\t\"\n        \"adds r14, r11 \\n\\t\"\n        \"adcs r9, r12 \\n\\t\"\n        \"adc r10, #0 \\n\\t\"\n        \"umull r11, r12, r5, r7 \\n\\t\"\n        \"adds r14, r11 \\n\\t\"\n        \"adcs r9, r12 \\n\\t\"\n        \"adc r10, #0 \\n\\t\"\n        \"umull r11, r12, r3, r6 \\n\\t\"\n        \"adds r14, r11 \\n\\t\"\n        \"adcs r9, r12 \\n\\t\"\n        \"adc r10, #0 \\n\\t\"\n        \"ldr r11, [r0] \\n\\t\"\n        \"adds r14, r11 \\n\\t\"\n        \"adcs r9, #0 \\n\\t\"\n        \"adc r10, #0 \\n\\t\"\n        \"stmia r0!, {r14} \\n\\t\"\n\n        \"ldmia r2!, {r6} \\n\\t\"\n        \"mov r11, #0 \\n\\t\"\n        \"umull r12, r14, r4, r6 \\n\\t\"\n        \"adds r9, r12 \\n\\t\"\n        \"adcs r10, r14 \\n\\t\"\n        \"adc r11, #0 \\n\\t\"\n        \"umull r12, r14, r5, r8 \\n\\t\"\n        \"adds r9, r12 \\n\\t\"\n        \"adcs r10, r14 \\n\\t\"\n        \"adc r11, #0 \\n\\t\"\n        \"umull r12, r14, r3, r7 \\n\\t\"\n        \"adds r9, r12 \\n\\t\"\n        \"adcs r10, r14 \\n\\t\"\n        \"adc r11, #0 \\n\\t\"\n        \"ldr r12, [r0] \\n\\t\"\n        \"adds r9, r12 \\n\\t\"\n        \"adcs r10, #0 \\n\\t\"\n        \"adc r11, #0 \\n\\t\"\n        \"stmia r0!, {r9} \\n\\t\"\n\n        \"mov r12, #0 \\n\\t\"\n        \"umull r14, r9, r5, r6 \\n\\t\"\n        \"adds r10, r14 \\n\\t\"\n        \"adcs r11, r9 \\n\\t\"\n        \"adc r12, #0 \\n\\t\"\n        \"umull r14, r9, r3, r8 \\n\\t\"\n        \"adds r10, r14 \\n\\t\"\n        \"adcs r11, r9 \\n\\t\"\n        \"adc r12, #0 \\n\\t\"\n        \"stmia r0!, {r10} \\n\\t\"\n\n        \"umull r9, r10, r3, r6 \\n\\t\"\n        \"adds r11, r9 \\n\\t\"\n        \"adc r12, r10 \\n\\t\"\n        \"stmia r0!, {r11, r12} \\n\\t\"\n\n        \"sub r0, 44 \\n\\t\"\n        \"sub r1, 16 \\n\\t\"\n        \"sub r2, 28 \\n\\t\"\n        \"ldmia r1!, {r3,r4,r5} \\n\\t\"\n        \"ldmia r2!, {r6,r7,r8} \\n\\t\"\n\n        \"umull r9, r10, r3, r6 \\n\\t\"\n        \"stmia r0!, {r9} \\n\\t\"\n\n        \"mov r14, #0 \\n\\t\"\n        \"umull r9, r12, r3, r7 \\n\\t\"\n        \"adds r10, r9 \\n\\t\"\n        \"adc r12, #0 \\n\\t\"\n        \"umull r9, r11, r4, r6 \\n\\t\"\n        \"adds r10, r9 \\n\\t\"\n        \"adcs r12, r11 \\n\\t\"\n        \"adc r14, #0 \\n\\t\"\n        \"stmia r0!, {r10} \\n\\t\"\n\n        \"mov r9, #0 \\n\\t\"\n        \"umull r10, r11, r3, r8 \\n\\t\"\n        \"adds r12, r10 \\n\\t\"\n        \"adcs r14, r11 \\n\\t\"\n        \"adc r9, #0 \\n\\t\"\n        \"umull r10, r11, r4, r7 \\n\\t\"\n        \"adds r12, r10 \\n\\t\"\n        \"adcs r14, r11 \\n\\t\"\n        \"adc r9, #0 \\n\\t\"\n        \"umull r10, r11, r5, r6 \\n\\t\"\n        \"adds r12, r10 \\n\\t\"\n        \"adcs r14, r11 \\n\\t\"\n        \"adc r9, #0 \\n\\t\"\n        \"stmia r0!, {r12} \\n\\t\"\n\n        \"ldmia r1!, {r3} \\n\\t\"\n        \"mov r10, #0 \\n\\t\"\n        \"umull r11, r12, r4, r8 \\n\\t\"\n        \"adds r14, r11 \\n\\t\"\n        \"adcs r9, r12 \\n\\t\"\n        \"adc r10, #0 \\n\\t\"\n        \"umull r11, r12, r5, r7 \\n\\t\"\n        \"adds r14, r11 \\n\\t\"\n        \"adcs r9, r12 \\n\\t\"\n        \"adc r10, #0 \\n\\t\"\n        \"umull r11, r12, r3, r6 \\n\\t\"\n        \"adds r14, r11 \\n\\t\"\n        \"adcs r9, r12 \\n\\t\"\n        \"adc r10, #0 \\n\\t\"\n        \"ldr r11, [r0] \\n\\t\"\n        \"adds r14, r11 \\n\\t\"\n        \"adcs r9, #0 \\n\\t\"\n        \"adc r10, #0 \\n\\t\"\n        \"stmia r0!, {r14} \\n\\t\"\n\n        \"ldmia r1!, {r4} \\n\\t\"\n        \"mov r11, #0 \\n\\t\"\n        \"umull r12, r14, r5, r8 \\n\\t\"\n        \"adds r9, r12 \\n\\t\"\n        \"adcs r10, r14 \\n\\t\"\n        \"adc r11, #0 \\n\\t\"\n        \"umull r12, r14, r3, r7 \\n\\t\"\n        \"adds r9, r12 \\n\\t\"\n        \"adcs r10, r14 \\n\\t\"\n        \"adc r11, #0 \\n\\t\"\n        \"umull r12, r14, r4, r6 \\n\\t\"\n        \"adds r9, r12 \\n\\t\"\n        \"adcs r10, r14 \\n\\t\"\n        \"adc r11, #0 \\n\\t\"\n        \"ldr r12, [r0] \\n\\t\"\n        \"adds r9, r12 \\n\\t\"\n        \"adcs r10, #0 \\n\\t\"\n        \"adc r11, #0 \\n\\t\"\n        \"stmia r0!, {r9} \\n\\t\"\n\n        \"ldmia r1!, {r5} \\n\\t\"\n        \"mov r12, #0 \\n\\t\"\n        \"umull r14, r9, r3, r8 \\n\\t\"\n        \"adds r10, r14 \\n\\t\"\n        \"adcs r11, r9 \\n\\t\"\n        \"adc r12, #0 \\n\\t\"\n        \"umull r14, r9, r4, r7 \\n\\t\"\n        \"adds r10, r14 \\n\\t\"\n        \"adcs r11, r9 \\n\\t\"\n        \"adc r12, #0 \\n\\t\"\n        \"umull r14, r9, r5, r6 \\n\\t\"\n        \"adds r10, r14 \\n\\t\"\n        \"adcs r11, r9 \\n\\t\"\n        \"adc r12, #0 \\n\\t\"\n        \"ldr r14, [r0] \\n\\t\"\n        \"adds r10, r14 \\n\\t\"\n        \"adcs r11, #0 \\n\\t\"\n        \"adc r12, #0 \\n\\t\"\n        \"stmia r0!, {r10} \\n\\t\"\n\n        \"ldmia r1!, {r3} \\n\\t\"\n        \"mov r14, #0 \\n\\t\"\n        \"umull r9, r10, r4, r8 \\n\\t\"\n        \"adds r11, r9 \\n\\t\"\n        \"adcs r12, r10 \\n\\t\"\n        \"adc r14, #0 \\n\\t\"\n        \"umull r9, r10, r5, r7 \\n\\t\"\n        \"adds r11, r9 \\n\\t\"\n        \"adcs r12, r10 \\n\\t\"\n        \"adc r14, #0 \\n\\t\"\n        \"umull r9, r10, r3, r6 \\n\\t\"\n        \"adds r11, r9 \\n\\t\"\n        \"adcs r12, r10 \\n\\t\"\n        \"adc r14, #0 \\n\\t\"\n        \"ldr r9, [r0] \\n\\t\"\n        \"adds r11, r9 \\n\\t\"\n        \"adcs r12, #0 \\n\\t\"\n        \"adc r14, #0 \\n\\t\"\n        \"stmia r0!, {r11} \\n\\t\"\n\n        \"ldmia r2!, {r6} \\n\\t\"\n        \"mov r9, #0 \\n\\t\"\n        \"umull r10, r11, r4, r6 \\n\\t\"\n        \"adds r12, r10 \\n\\t\"\n        \"adcs r14, r11 \\n\\t\"\n        \"adc r9, #0 \\n\\t\"\n        \"umull r10, r11, r5, r8 \\n\\t\"\n        \"adds r12, r10 \\n\\t\"\n        \"adcs r14, r11 \\n\\t\"\n        \"adc r9, #0 \\n\\t\"\n        \"umull r10, r11, r3, r7 \\n\\t\"\n        \"adds r12, r10 \\n\\t\"\n        \"adcs r14, r11 \\n\\t\"\n        \"adc r9, #0 \\n\\t\"\n        \"ldr r10, [r0] \\n\\t\"\n        \"adds r12, r10 \\n\\t\"\n        \"adcs r14, #0 \\n\\t\"\n        \"adc r9, #0 \\n\\t\"\n        \"stmia r0!, {r12} \\n\\t\"\n\n        \"ldmia r2!, {r7} \\n\\t\"\n        \"mov r10, #0 \\n\\t\"\n        \"umull r11, r12, r4, r7 \\n\\t\"\n        \"adds r14, r11 \\n\\t\"\n        \"adcs r9, r12 \\n\\t\"\n        \"adc r10, #0 \\n\\t\"\n        \"umull r11, r12, r5, r6 \\n\\t\"\n        \"adds r14, r11 \\n\\t\"\n        \"adcs r9, r12 \\n\\t\"\n        \"adc r10, #0 \\n\\t\"\n        \"umull r11, r12, r3, r8 \\n\\t\"\n        \"adds r14, r11 \\n\\t\"\n        \"adcs r9, r12 \\n\\t\"\n        \"adc r10, #0 \\n\\t\"\n        \"ldr r11, [r0] \\n\\t\"\n        \"adds r14, r11 \\n\\t\"\n        \"adcs r9, #0 \\n\\t\"\n        \"adc r10, #0 \\n\\t\"\n        \"stmia r0!, {r14} \\n\\t\"\n\n        \"ldmia r2!, {r8} \\n\\t\"\n        \"mov r11, #0 \\n\\t\"\n        \"umull r12, r14, r4, r8 \\n\\t\"\n        \"adds r9, r12 \\n\\t\"\n        \"adcs r10, r14 \\n\\t\"\n        \"adc r11, #0 \\n\\t\"\n        \"umull r12, r14, r5, r7 \\n\\t\"\n        \"adds r9, r12 \\n\\t\"\n        \"adcs r10, r14 \\n\\t\"\n        \"adc r11, #0 \\n\\t\"\n        \"umull r12, r14, r3, r6 \\n\\t\"\n        \"adds r9, r12 \\n\\t\"\n        \"adcs r10, r14 \\n\\t\"\n        \"adc r11, #0 \\n\\t\"\n        \"ldr r12, [r0] \\n\\t\"\n        \"adds r9, r12 \\n\\t\"\n        \"adcs r10, #0 \\n\\t\"\n        \"adc r11, #0 \\n\\t\"\n        \"stmia r0!, {r9} \\n\\t\"\n\n        \"ldmia r2!, {r6} \\n\\t\"\n        \"mov r12, #0 \\n\\t\"\n        \"umull r14, r9, r4, r6 \\n\\t\"\n        \"adds r10, r14 \\n\\t\"\n        \"adcs r11, r9 \\n\\t\"\n        \"adc r12, #0 \\n\\t\"\n        \"umull r14, r9, r5, r8 \\n\\t\"\n        \"adds r10, r14 \\n\\t\"\n        \"adcs r11, r9 \\n\\t\"\n        \"adc r12, #0 \\n\\t\"\n        \"umull r14, r9, r3, r7 \\n\\t\"\n        \"adds r10, r14 \\n\\t\"\n        \"adcs r11, r9 \\n\\t\"\n        \"adc r12, #0 \\n\\t\"\n        \"ldr r14, [r0] \\n\\t\"\n        \"adds r10, r14 \\n\\t\"\n        \"adcs r11, #0 \\n\\t\"\n        \"adc r12, #0 \\n\\t\"\n        \"stmia r0!, {r10} \\n\\t\"\n\n        \"mov r14, #0 \\n\\t\"\n        \"umull r9, r10, r5, r6 \\n\\t\"\n        \"adds r11, r9 \\n\\t\"\n        \"adcs r12, r10 \\n\\t\"\n        \"adc r14, #0 \\n\\t\"\n        \"umull r9, r10, r3, r8 \\n\\t\"\n        \"adds r11, r9 \\n\\t\"\n        \"adcs r12, r10 \\n\\t\"\n        \"adc r14, #0 \\n\\t\"\n        \"stmia r0!, {r11} \\n\\t\"\n\n        \"umull r10, r11, r3, r6 \\n\\t\"\n        \"adds r12, r10 \\n\\t\"\n        \"adc r14, r11 \\n\\t\"\n        \"stmia r0!, {r12, r14} \\n\\t\"\n    #if (uECC_PLATFORM != uECC_arm_thumb2)\n        \".syntax divided \\n\\t\"\n    #endif\n        : \"+r\" (r0), \"+r\" (r1), \"+r\" (r2)\n        :\n        : \"r3\", \"r4\", \"r5\", \"r6\", \"r7\", \"r8\", \"r9\", \"r10\", \"r11\", \"r12\", \"r14\", \"cc\", \"memory\"\n    );\n}\n#define asm_mult 1\n#endif /* (uECC_WORDS == 7) */\n\n#if (uECC_WORDS == 8)\nstatic void vli_mult(uint32_t *result, const uint32_t *left, const uint32_t *right) {\n    register uint32_t *r0 __asm__(\"r0\") = result;\n    register const uint32_t *r1 __asm__(\"r1\") = left;\n    register const uint32_t *r2 __asm__(\"r2\") = right;\n\n    __asm__ volatile (\n        \".syntax unified \\n\\t\"\n        \"add r0, 24 \\n\\t\"\n        \"add r2, 24 \\n\\t\"\n        \"ldmia r1!, {r3,r4} \\n\\t\"\n        \"ldmia r2!, {r6,r7} \\n\\t\"\n\n        \"umull r11, r12, r3, r6 \\n\\t\"\n        \"stmia r0!, {r11} \\n\\t\"\n\n        \"mov r10, #0 \\n\\t\"\n        \"umull r11, r9, r3, r7 \\n\\t\"\n        \"adds r12, r11 \\n\\t\"\n        \"adc r9, #0 \\n\\t\"\n        \"umull r11, r14, r4, r6 \\n\\t\"\n        \"adds r12, r11 \\n\\t\"\n        \"adcs r9, r14 \\n\\t\"\n        \"adc r10, #0 \\n\\t\"\n        \"stmia r0!, {r12} \\n\\t\"\n\n        \"umull r12, r14, r4, r7 \\n\\t\"\n        \"adds r9, r12 \\n\\t\"\n        \"adc r10, r14 \\n\\t\"\n        \"stmia r0!, {r9, r10} \\n\\t\"\n\n        \"sub r0, 28 \\n\\t\"\n        \"sub r2, 20 \\n\\t\"\n        \"ldmia r2!, {r6,r7,r8} \\n\\t\"\n        \"ldmia r1!, {r5} \\n\\t\"\n\n        \"umull r11, r12, r3, r6 \\n\\t\"\n        \"stmia r0!, {r11} \\n\\t\"\n\n        \"mov r10, #0 \\n\\t\"\n        \"umull r11, r9, r3, r7 \\n\\t\"\n        \"adds r12, r11 \\n\\t\"\n        \"adc r9, #0 \\n\\t\"\n        \"umull r11, r14, r4, r6 \\n\\t\"\n        \"adds r12, r11 \\n\\t\"\n        \"adcs r9, r14 \\n\\t\"\n        \"adc r10, #0 \\n\\t\"\n        \"stmia r0!, {r12} \\n\\t\"\n\n        \"mov r11, #0 \\n\\t\"\n        \"umull r12, r14, r3, r8 \\n\\t\"\n        \"adds r9, r12 \\n\\t\"\n        \"adcs r10, r14 \\n\\t\"\n        \"adc r11, #0 \\n\\t\"\n        \"umull r12, r14, r4, r7 \\n\\t\"\n        \"adds r9, r12 \\n\\t\"\n        \"adcs r10, r14 \\n\\t\"\n        \"adc r11, #0 \\n\\t\"\n        \"umull r12, r14, r5, r6 \\n\\t\"\n        \"adds r9, r12 \\n\\t\"\n        \"adcs r10, r14 \\n\\t\"\n        \"adc r11, #0 \\n\\t\"\n        \"stmia r0!, {r9} \\n\\t\"\n\n        \"ldmia r1!, {r3} \\n\\t\"\n        \"mov r12, #0 \\n\\t\"\n        \"umull r14, r9, r4, r8 \\n\\t\"\n        \"adds r10, r14 \\n\\t\"\n        \"adcs r11, r9 \\n\\t\"\n        \"adc r12, #0 \\n\\t\"\n        \"umull r14, r9, r5, r7 \\n\\t\"\n        \"adds r10, r14 \\n\\t\"\n        \"adcs r11, r9 \\n\\t\"\n        \"adc r12, #0 \\n\\t\"\n        \"umull r14, r9, r3, r6 \\n\\t\"\n        \"adds r10, r14 \\n\\t\"\n        \"adcs r11, r9 \\n\\t\"\n        \"adc r12, #0 \\n\\t\"\n        \"ldr r14, [r0] \\n\\t\"\n        \"adds r10, r14 \\n\\t\"\n        \"adcs r11, #0 \\n\\t\"\n        \"adc r12, #0 \\n\\t\"\n        \"stmia r0!, {r10} \\n\\t\"\n\n        \"ldmia r1!, {r4} \\n\\t\"\n        \"mov r14, #0 \\n\\t\"\n        \"umull r9, r10, r5, r8 \\n\\t\"\n        \"adds r11, r9 \\n\\t\"\n        \"adcs r12, r10 \\n\\t\"\n        \"adc r14, #0 \\n\\t\"\n        \"umull r9, r10, r3, r7 \\n\\t\"\n        \"adds r11, r9 \\n\\t\"\n        \"adcs r12, r10 \\n\\t\"\n        \"adc r14, #0 \\n\\t\"\n        \"umull r9, r10, r4, r6 \\n\\t\"\n        \"adds r11, r9 \\n\\t\"\n        \"adcs r12, r10 \\n\\t\"\n        \"adc r14, #0 \\n\\t\"\n        \"ldr r9, [r0] \\n\\t\"\n        \"adds r11, r9 \\n\\t\"\n        \"adcs r12, #0 \\n\\t\"\n        \"adc r14, #0 \\n\\t\"\n        \"stmia r0!, {r11} \\n\\t\"\n\n        \"ldmia r2!, {r6} \\n\\t\"\n        \"mov r9, #0 \\n\\t\"\n        \"umull r10, r11, r5, r6 \\n\\t\"\n        \"adds r12, r10 \\n\\t\"\n        \"adcs r14, r11 \\n\\t\"\n        \"adc r9, #0 \\n\\t\"\n        \"umull r10, r11, r3, r8 \\n\\t\"\n        \"adds r12, r10 \\n\\t\"\n        \"adcs r14, r11 \\n\\t\"\n        \"adc r9, #0 \\n\\t\"\n        \"umull r10, r11, r4, r7 \\n\\t\"\n        \"adds r12, r10 \\n\\t\"\n        \"adcs r14, r11 \\n\\t\"\n        \"adc r9, #0 \\n\\t\"\n        \"ldr r10, [r0] \\n\\t\"\n        \"adds r12, r10 \\n\\t\"\n        \"adcs r14, #0 \\n\\t\"\n        \"adc r9, #0 \\n\\t\"\n        \"stmia r0!, {r12} \\n\\t\"\n\n        \"ldmia r2!, {r7} \\n\\t\"\n        \"mov r10, #0 \\n\\t\"\n        \"umull r11, r12, r5, r7 \\n\\t\"\n        \"adds r14, r11 \\n\\t\"\n        \"adcs r9, r12 \\n\\t\"\n        \"adc r10, #0 \\n\\t\"\n        \"umull r11, r12, r3, r6 \\n\\t\"\n        \"adds r14, r11 \\n\\t\"\n        \"adcs r9, r12 \\n\\t\"\n        \"adc r10, #0 \\n\\t\"\n        \"umull r11, r12, r4, r8 \\n\\t\"\n        \"adds r14, r11 \\n\\t\"\n        \"adcs r9, r12 \\n\\t\"\n        \"adc r10, #0 \\n\\t\"\n        \"ldr r11, [r0] \\n\\t\"\n        \"adds r14, r11 \\n\\t\"\n        \"adcs r9, #0 \\n\\t\"\n        \"adc r10, #0 \\n\\t\"\n        \"stmia r0!, {r14} \\n\\t\"\n\n        \"mov r11, #0 \\n\\t\"\n        \"umull r12, r14, r3, r7 \\n\\t\"\n        \"adds r9, r12 \\n\\t\"\n        \"adcs r10, r14 \\n\\t\"\n        \"adc r11, #0 \\n\\t\"\n        \"umull r12, r14, r4, r6 \\n\\t\"\n        \"adds r9, r12 \\n\\t\"\n        \"adcs r10, r14 \\n\\t\"\n        \"adc r11, #0 \\n\\t\"\n        \"stmia r0!, {r9} \\n\\t\"\n\n        \"umull r14, r9, r4, r7 \\n\\t\"\n        \"adds r10, r14 \\n\\t\"\n        \"adc r11, r9 \\n\\t\"\n        \"stmia r0!, {r10, r11} \\n\\t\"\n\n        \"sub r0, 52 \\n\\t\"\n        \"sub r1, 20 \\n\\t\"\n        \"sub r2, 32 \\n\\t\"\n        \"ldmia r1!, {r3,r4,r5} \\n\\t\"\n        \"ldmia r2!, {r6,r7,r8} \\n\\t\"\n\n        \"umull r11, r12, r3, r6 \\n\\t\"\n        \"stmia r0!, {r11} \\n\\t\"\n\n        \"mov r10, #0 \\n\\t\"\n        \"umull r11, r9, r3, r7 \\n\\t\"\n        \"adds r12, r11 \\n\\t\"\n        \"adc r9, #0 \\n\\t\"\n        \"umull r11, r14, r4, r6 \\n\\t\"\n        \"adds r12, r11 \\n\\t\"\n        \"adcs r9, r14 \\n\\t\"\n        \"adc r10, #0 \\n\\t\"\n        \"stmia r0!, {r12} \\n\\t\"\n\n        \"mov r11, #0 \\n\\t\"\n        \"umull r12, r14, r3, r8 \\n\\t\"\n        \"adds r9, r12 \\n\\t\"\n        \"adcs r10, r14 \\n\\t\"\n        \"adc r11, #0 \\n\\t\"\n        \"umull r12, r14, r4, r7 \\n\\t\"\n        \"adds r9, r12 \\n\\t\"\n        \"adcs r10, r14 \\n\\t\"\n        \"adc r11, #0 \\n\\t\"\n        \"umull r12, r14, r5, r6 \\n\\t\"\n        \"adds r9, r12 \\n\\t\"\n        \"adcs r10, r14 \\n\\t\"\n        \"adc r11, #0 \\n\\t\"\n        \"stmia r0!, {r9} \\n\\t\"\n\n        \"ldmia r1!, {r3} \\n\\t\"\n        \"mov r12, #0 \\n\\t\"\n        \"umull r14, r9, r4, r8 \\n\\t\"\n        \"adds r10, r14 \\n\\t\"\n        \"adcs r11, r9 \\n\\t\"\n        \"adc r12, #0 \\n\\t\"\n        \"umull r14, r9, r5, r7 \\n\\t\"\n        \"adds r10, r14 \\n\\t\"\n        \"adcs r11, r9 \\n\\t\"\n        \"adc r12, #0 \\n\\t\"\n        \"umull r14, r9, r3, r6 \\n\\t\"\n        \"adds r10, r14 \\n\\t\"\n        \"adcs r11, r9 \\n\\t\"\n        \"adc r12, #0 \\n\\t\"\n        \"ldr r14, [r0] \\n\\t\"\n        \"adds r10, r14 \\n\\t\"\n        \"adcs r11, #0 \\n\\t\"\n        \"adc r12, #0 \\n\\t\"\n        \"stmia r0!, {r10} \\n\\t\"\n\n        \"ldmia r1!, {r4} \\n\\t\"\n        \"mov r14, #0 \\n\\t\"\n        \"umull r9, r10, r5, r8 \\n\\t\"\n        \"adds r11, r9 \\n\\t\"\n        \"adcs r12, r10 \\n\\t\"\n        \"adc r14, #0 \\n\\t\"\n        \"umull r9, r10, r3, r7 \\n\\t\"\n        \"adds r11, r9 \\n\\t\"\n        \"adcs r12, r10 \\n\\t\"\n        \"adc r14, #0 \\n\\t\"\n        \"umull r9, r10, r4, r6 \\n\\t\"\n        \"adds r11, r9 \\n\\t\"\n        \"adcs r12, r10 \\n\\t\"\n        \"adc r14, #0 \\n\\t\"\n        \"ldr r9, [r0] \\n\\t\"\n        \"adds r11, r9 \\n\\t\"\n        \"adcs r12, #0 \\n\\t\"\n        \"adc r14, #0 \\n\\t\"\n        \"stmia r0!, {r11} \\n\\t\"\n\n        \"ldmia r1!, {r5} \\n\\t\"\n        \"mov r9, #0 \\n\\t\"\n        \"umull r10, r11, r3, r8 \\n\\t\"\n        \"adds r12, r10 \\n\\t\"\n        \"adcs r14, r11 \\n\\t\"\n        \"adc r9, #0 \\n\\t\"\n        \"umull r10, r11, r4, r7 \\n\\t\"\n        \"adds r12, r10 \\n\\t\"\n        \"adcs r14, r11 \\n\\t\"\n        \"adc r9, #0 \\n\\t\"\n        \"umull r10, r11, r5, r6 \\n\\t\"\n        \"adds r12, r10 \\n\\t\"\n        \"adcs r14, r11 \\n\\t\"\n        \"adc r9, #0 \\n\\t\"\n        \"ldr r10, [r0] \\n\\t\"\n        \"adds r12, r10 \\n\\t\"\n        \"adcs r14, #0 \\n\\t\"\n        \"adc r9, #0 \\n\\t\"\n        \"stmia r0!, {r12} \\n\\t\"\n\n        \"ldmia r1!, {r3} \\n\\t\"\n        \"mov r10, #0 \\n\\t\"\n        \"umull r11, r12, r4, r8 \\n\\t\"\n        \"adds r14, r11 \\n\\t\"\n        \"adcs r9, r12 \\n\\t\"\n        \"adc r10, #0 \\n\\t\"\n        \"umull r11, r12, r5, r7 \\n\\t\"\n        \"adds r14, r11 \\n\\t\"\n        \"adcs r9, r12 \\n\\t\"\n        \"adc r10, #0 \\n\\t\"\n        \"umull r11, r12, r3, r6 \\n\\t\"\n        \"adds r14, r11 \\n\\t\"\n        \"adcs r9, r12 \\n\\t\"\n        \"adc r10, #0 \\n\\t\"\n        \"ldr r11, [r0] \\n\\t\"\n        \"adds r14, r11 \\n\\t\"\n        \"adcs r9, #0 \\n\\t\"\n        \"adc r10, #0 \\n\\t\"\n        \"stmia r0!, {r14} \\n\\t\"\n\n        \"ldmia r1!, {r4} \\n\\t\"\n        \"mov r11, #0 \\n\\t\"\n        \"umull r12, r14, r5, r8 \\n\\t\"\n        \"adds r9, r12 \\n\\t\"\n        \"adcs r10, r14 \\n\\t\"\n        \"adc r11, #0 \\n\\t\"\n        \"umull r12, r14, r3, r7 \\n\\t\"\n        \"adds r9, r12 \\n\\t\"\n        \"adcs r10, r14 \\n\\t\"\n        \"adc r11, #0 \\n\\t\"\n        \"umull r12, r14, r4, r6 \\n\\t\"\n        \"adds r9, r12 \\n\\t\"\n        \"adcs r10, r14 \\n\\t\"\n        \"adc r11, #0 \\n\\t\"\n        \"ldr r12, [r0] \\n\\t\"\n        \"adds r9, r12 \\n\\t\"\n        \"adcs r10, #0 \\n\\t\"\n        \"adc r11, #0 \\n\\t\"\n        \"stmia r0!, {r9} \\n\\t\"\n\n        \"ldmia r2!, {r6} \\n\\t\"\n        \"mov r12, #0 \\n\\t\"\n        \"umull r14, r9, r5, r6 \\n\\t\"\n        \"adds r10, r14 \\n\\t\"\n        \"adcs r11, r9 \\n\\t\"\n        \"adc r12, #0 \\n\\t\"\n        \"umull r14, r9, r3, r8 \\n\\t\"\n        \"adds r10, r14 \\n\\t\"\n        \"adcs r11, r9 \\n\\t\"\n        \"adc r12, #0 \\n\\t\"\n        \"umull r14, r9, r4, r7 \\n\\t\"\n        \"adds r10, r14 \\n\\t\"\n        \"adcs r11, r9 \\n\\t\"\n        \"adc r12, #0 \\n\\t\"\n        \"ldr r14, [r0] \\n\\t\"\n        \"adds r10, r14 \\n\\t\"\n        \"adcs r11, #0 \\n\\t\"\n        \"adc r12, #0 \\n\\t\"\n        \"stmia r0!, {r10} \\n\\t\"\n\n        \"ldmia r2!, {r7} \\n\\t\"\n        \"mov r14, #0 \\n\\t\"\n        \"umull r9, r10, r5, r7 \\n\\t\"\n        \"adds r11, r9 \\n\\t\"\n        \"adcs r12, r10 \\n\\t\"\n        \"adc r14, #0 \\n\\t\"\n        \"umull r9, r10, r3, r6 \\n\\t\"\n        \"adds r11, r9 \\n\\t\"\n        \"adcs r12, r10 \\n\\t\"\n        \"adc r14, #0 \\n\\t\"\n        \"umull r9, r10, r4, r8 \\n\\t\"\n        \"adds r11, r9 \\n\\t\"\n        \"adcs r12, r10 \\n\\t\"\n        \"adc r14, #0 \\n\\t\"\n        \"ldr r9, [r0] \\n\\t\"\n        \"adds r11, r9 \\n\\t\"\n        \"adcs r12, #0 \\n\\t\"\n        \"adc r14, #0 \\n\\t\"\n        \"stmia r0!, {r11} \\n\\t\"\n\n        \"ldmia r2!, {r8} \\n\\t\"\n        \"mov r9, #0 \\n\\t\"\n        \"umull r10, r11, r5, r8 \\n\\t\"\n        \"adds r12, r10 \\n\\t\"\n        \"adcs r14, r11 \\n\\t\"\n        \"adc r9, #0 \\n\\t\"\n        \"umull r10, r11, r3, r7 \\n\\t\"\n        \"adds r12, r10 \\n\\t\"\n        \"adcs r14, r11 \\n\\t\"\n        \"adc r9, #0 \\n\\t\"\n        \"umull r10, r11, r4, r6 \\n\\t\"\n        \"adds r12, r10 \\n\\t\"\n        \"adcs r14, r11 \\n\\t\"\n        \"adc r9, #0 \\n\\t\"\n        \"ldr r10, [r0] \\n\\t\"\n        \"adds r12, r10 \\n\\t\"\n        \"adcs r14, #0 \\n\\t\"\n        \"adc r9, #0 \\n\\t\"\n        \"stmia r0!, {r12} \\n\\t\"\n\n        \"ldmia r2!, {r6} \\n\\t\"\n        \"mov r10, #0 \\n\\t\"\n        \"umull r11, r12, r5, r6 \\n\\t\"\n        \"adds r14, r11 \\n\\t\"\n        \"adcs r9, r12 \\n\\t\"\n        \"adc r10, #0 \\n\\t\"\n        \"umull r11, r12, r3, r8 \\n\\t\"\n        \"adds r14, r11 \\n\\t\"\n        \"adcs r9, r12 \\n\\t\"\n        \"adc r10, #0 \\n\\t\"\n        \"umull r11, r12, r4, r7 \\n\\t\"\n        \"adds r14, r11 \\n\\t\"\n        \"adcs r9, r12 \\n\\t\"\n        \"adc r10, #0 \\n\\t\"\n        \"ldr r11, [r0] \\n\\t\"\n        \"adds r14, r11 \\n\\t\"\n        \"adcs r9, #0 \\n\\t\"\n        \"adc r10, #0 \\n\\t\"\n        \"stmia r0!, {r14} \\n\\t\"\n\n        \"ldmia r2!, {r7} \\n\\t\"\n        \"mov r11, #0 \\n\\t\"\n        \"umull r12, r14, r5, r7 \\n\\t\"\n        \"adds r9, r12 \\n\\t\"\n        \"adcs r10, r14 \\n\\t\"\n        \"adc r11, #0 \\n\\t\"\n        \"umull r12, r14, r3, r6 \\n\\t\"\n        \"adds r9, r12 \\n\\t\"\n        \"adcs r10, r14 \\n\\t\"\n        \"adc r11, #0 \\n\\t\"\n        \"umull r12, r14, r4, r8 \\n\\t\"\n        \"adds r9, r12 \\n\\t\"\n        \"adcs r10, r14 \\n\\t\"\n        \"adc r11, #0 \\n\\t\"\n        \"ldr r12, [r0] \\n\\t\"\n        \"adds r9, r12 \\n\\t\"\n        \"adcs r10, #0 \\n\\t\"\n        \"adc r11, #0 \\n\\t\"\n        \"stmia r0!, {r9} \\n\\t\"\n\n        \"mov r12, #0 \\n\\t\"\n        \"umull r14, r9, r3, r7 \\n\\t\"\n        \"adds r10, r14 \\n\\t\"\n        \"adcs r11, r9 \\n\\t\"\n        \"adc r12, #0 \\n\\t\"\n        \"umull r14, r9, r4, r6 \\n\\t\"\n        \"adds r10, r14 \\n\\t\"\n        \"adcs r11, r9 \\n\\t\"\n        \"adc r12, #0 \\n\\t\"\n        \"stmia r0!, {r10} \\n\\t\"\n\n        \"umull r9, r10, r4, r7 \\n\\t\"\n        \"adds r11, r9 \\n\\t\"\n        \"adc r12, r10 \\n\\t\"\n        \"stmia r0!, {r11, r12} \\n\\t\"\n    #if (uECC_PLATFORM != uECC_arm_thumb2)\n        \".syntax divided \\n\\t\"\n    #endif\n        : \"+r\" (r0), \"+r\" (r1), \"+r\" (r2)\n        :\n        : \"r3\", \"r4\", \"r5\", \"r6\", \"r7\", \"r8\", \"r9\", \"r10\", \"r11\", \"r12\", \"r14\", \"cc\", \"memory\"\n    );\n}\n#define asm_mult 1\n#endif /* (uECC_WORDS == 8) */\n\n#if uECC_SQUARE_FUNC\n#if (uECC_WORDS == 5)\nstatic void vli_square(uint32_t *result, const uint32_t *left) {\n    register uint32_t *r0 __asm__(\"r0\") = result;\n    register const uint32_t *r1 __asm__(\"r1\") = left;\n\n    __asm__ volatile (\n        \".syntax unified \\n\\t\"\n        \"ldmia r1!, {r2,r3,r4,r5,r6} \\n\\t\"\n\n        \"umull r11, r12, r2, r2 \\n\\t\"\n        \"stmia r0!, {r11} \\n\\t\"\n\n        \"mov r9, #0 \\n\\t\"\n        \"umull r10, r11, r2, r3 \\n\\t\"\n        \"adds r12, r10 \\n\\t\"\n        \"adcs r8, r11, #0 \\n\\t\"\n        \"adc r9, #0 \\n\\t\"\n        \"adds r12, r10 \\n\\t\"\n        \"adcs r8, r11 \\n\\t\"\n        \"adc r9, #0 \\n\\t\"\n        \"stmia r0!, {r12} \\n\\t\"\n\n        \"mov r10, #0 \\n\\t\"\n        \"umull r11, r12, r2, r4 \\n\\t\"\n        \"adds r11, r11 \\n\\t\"\n        \"adcs r12, r12 \\n\\t\"\n        \"adc r10, #0 \\n\\t\"\n        \"adds r8, r11 \\n\\t\"\n        \"adcs r9, r12 \\n\\t\"\n        \"adc r10, #0 \\n\\t\"\n        \"umull r11, r12, r3, r3 \\n\\t\"\n        \"adds r8, r11 \\n\\t\"\n        \"adcs r9, r12 \\n\\t\"\n        \"adc r10, #0 \\n\\t\"\n        \"stmia r0!, {r8} \\n\\t\"\n\n        \"mov r12, #0 \\n\\t\"\n        \"umull r8, r11, r2, r5 \\n\\t\"\n        \"umull r1, r14, r3, r4 \\n\\t\"\n        \"adds r8, r1 \\n\\t\"\n        \"adcs r11, r14 \\n\\t\"\n        \"adc r12, #0 \\n\\t\"\n        \"adds r8, r8 \\n\\t\"\n        \"adcs r11, r11 \\n\\t\"\n        \"adc r12, r12 \\n\\t\"\n        \"adds r8, r9 \\n\\t\"\n        \"adcs r11, r10 \\n\\t\"\n        \"adc r12, #0 \\n\\t\"\n        \"stmia r0!, {r8} \\n\\t\"\n\n        \"mov r10, #0 \\n\\t\"\n        \"umull r8, r9, r2, r6 \\n\\t\"\n        \"umull r1, r14, r3, r5 \\n\\t\"\n        \"adds r8, r1 \\n\\t\"\n        \"adcs r9, r14 \\n\\t\"\n        \"adc r10, #0 \\n\\t\"\n        \"adds r8, r8 \\n\\t\"\n        \"adcs r9, r9 \\n\\t\"\n        \"adc r10, r10 \\n\\t\"\n        \"umull r1, r14, r4, r4 \\n\\t\"\n        \"adds r8, r1 \\n\\t\"\n        \"adcs r9, r14 \\n\\t\"\n        \"adc r10, #0 \\n\\t\"\n        \"adds r8, r11 \\n\\t\"\n        \"adcs r9, r12 \\n\\t\"\n        \"adc r10, #0 \\n\\t\"\n        \"stmia r0!, {r8} \\n\\t\"\n\n        \"mov r12, #0 \\n\\t\"\n        \"umull r8, r11, r3, r6 \\n\\t\"\n        \"umull r1, r14, r4, r5 \\n\\t\"\n        \"adds r8, r1 \\n\\t\"\n        \"adcs r11, r14 \\n\\t\"\n        \"adc r12, #0 \\n\\t\"\n        \"adds r8, r8 \\n\\t\"\n        \"adcs r11, r11 \\n\\t\"\n        \"adc r12, r12 \\n\\t\"\n        \"adds r8, r9 \\n\\t\"\n        \"adcs r11, r10 \\n\\t\"\n        \"adc r12, #0 \\n\\t\"\n        \"stmia r0!, {r8} \\n\\t\"\n\n        \"mov r8, #0 \\n\\t\"\n        \"umull r1, r10, r4, r6 \\n\\t\"\n        \"adds r1, r1 \\n\\t\"\n        \"adcs r10, r10 \\n\\t\"\n        \"adc r8, #0 \\n\\t\"\n        \"adds r11, r1 \\n\\t\"\n        \"adcs r12, r10 \\n\\t\"\n        \"adc r8, #0 \\n\\t\"\n        \"umull r1, r10, r5, r5 \\n\\t\"\n        \"adds r11, r1 \\n\\t\"\n        \"adcs r12, r10 \\n\\t\"\n        \"adc r8, #0 \\n\\t\"\n        \"stmia r0!, {r11} \\n\\t\"\n\n        \"mov r11, #0 \\n\\t\"\n        \"umull r1, r10, r5, r6 \\n\\t\"\n        \"adds r1, r1 \\n\\t\"\n        \"adcs r10, r10 \\n\\t\"\n        \"adc r11, #0 \\n\\t\"\n        \"adds r12, r1 \\n\\t\"\n        \"adcs r8, r10 \\n\\t\"\n        \"adc r11, #0 \\n\\t\"\n        \"stmia r0!, {r12} \\n\\t\"\n\n        \"umull r1, r10, r6, r6 \\n\\t\"\n        \"adds r8, r1 \\n\\t\"\n        \"adcs r11, r10 \\n\\t\"\n        \"stmia r0!, {r8, r11} \\n\\t\"\n    #if (uECC_PLATFORM != uECC_arm_thumb2)\n        \".syntax divided \\n\\t\"\n    #endif\n        : \"+r\" (r0), \"+r\" (r1)\n        :\n        : \"r2\", \"r3\", \"r4\", \"r5\", \"r6\", \"r7\", \"r8\", \"r9\", \"r10\", \"r11\", \"r12\", \"r14\", \"cc\", \"memory\"\n    );\n}\n#define asm_square 1\n#endif /* (uECC_WORDS == 5) */\n\n#if (uECC_WORDS == 6)\nstatic void vli_square(uint32_t *result, const uint32_t *left) {\n    register uint32_t *r0 __asm__(\"r0\") = result;\n    register const uint32_t *r1 __asm__(\"r1\") = left;\n\n    __asm__ volatile (\n        \".syntax unified \\n\\t\"\n        \"ldmia r1!, {r2,r3,r4,r5,r6,r7} \\n\\t\"\n\n        \"umull r11, r12, r2, r2 \\n\\t\"\n        \"stmia r0!, {r11} \\n\\t\"\n\n        \"mov r9, #0 \\n\\t\"\n        \"umull r10, r11, r2, r3 \\n\\t\"\n        \"adds r12, r10 \\n\\t\"\n        \"adcs r8, r11, #0 \\n\\t\"\n        \"adc r9, #0 \\n\\t\"\n        \"adds r12, r10 \\n\\t\"\n        \"adcs r8, r11 \\n\\t\"\n        \"adc r9, #0 \\n\\t\"\n        \"stmia r0!, {r12} \\n\\t\"\n\n        \"mov r10, #0 \\n\\t\"\n        \"umull r11, r12, r2, r4 \\n\\t\"\n        \"adds r11, r11 \\n\\t\"\n        \"adcs r12, r12 \\n\\t\"\n        \"adc r10, #0 \\n\\t\"\n        \"adds r8, r11 \\n\\t\"\n        \"adcs r9, r12 \\n\\t\"\n        \"adc r10, #0 \\n\\t\"\n        \"umull r11, r12, r3, r3 \\n\\t\"\n        \"adds r8, r11 \\n\\t\"\n        \"adcs r9, r12 \\n\\t\"\n        \"adc r10, #0 \\n\\t\"\n        \"stmia r0!, {r8} \\n\\t\"\n\n        \"mov r12, #0 \\n\\t\"\n        \"umull r8, r11, r2, r5 \\n\\t\"\n        \"umull r1, r14, r3, r4 \\n\\t\"\n        \"adds r8, r1 \\n\\t\"\n        \"adcs r11, r14 \\n\\t\"\n        \"adc r12, #0 \\n\\t\"\n        \"adds r8, r8 \\n\\t\"\n        \"adcs r11, r11 \\n\\t\"\n        \"adc r12, r12 \\n\\t\"\n        \"adds r8, r9 \\n\\t\"\n        \"adcs r11, r10 \\n\\t\"\n        \"adc r12, #0 \\n\\t\"\n        \"stmia r0!, {r8} \\n\\t\"\n\n        \"mov r10, #0 \\n\\t\"\n        \"umull r8, r9, r2, r6 \\n\\t\"\n        \"umull r1, r14, r3, r5 \\n\\t\"\n        \"adds r8, r1 \\n\\t\"\n        \"adcs r9, r14 \\n\\t\"\n        \"adc r10, #0 \\n\\t\"\n        \"adds r8, r8 \\n\\t\"\n        \"adcs r9, r9 \\n\\t\"\n        \"adc r10, r10 \\n\\t\"\n        \"umull r1, r14, r4, r4 \\n\\t\"\n        \"adds r8, r1 \\n\\t\"\n        \"adcs r9, r14 \\n\\t\"\n        \"adc r10, #0 \\n\\t\"\n        \"adds r8, r11 \\n\\t\"\n        \"adcs r9, r12 \\n\\t\"\n        \"adc r10, #0 \\n\\t\"\n        \"stmia r0!, {r8} \\n\\t\"\n\n        \"mov r12, #0 \\n\\t\"\n        \"umull r8, r11, r2, r7 \\n\\t\"\n        \"umull r1, r14, r3, r6 \\n\\t\"\n        \"adds r8, r1 \\n\\t\"\n        \"adcs r11, r14 \\n\\t\"\n        \"adc r12, #0 \\n\\t\"\n        \"umull r1, r14, r4, r5 \\n\\t\"\n        \"adds r8, r1 \\n\\t\"\n        \"adcs r11, r14 \\n\\t\"\n        \"adc r12, #0 \\n\\t\"\n        \"adds r8, r8 \\n\\t\"\n        \"adcs r11, r11 \\n\\t\"\n        \"adc r12, r12 \\n\\t\"\n        \"adds r8, r9 \\n\\t\"\n        \"adcs r11, r10 \\n\\t\"\n        \"adc r12, #0 \\n\\t\"\n        \"stmia r0!, {r8} \\n\\t\"\n\n        \"mov r10, #0 \\n\\t\"\n        \"umull r8, r9, r3, r7 \\n\\t\"\n        \"umull r1, r14, r4, r6 \\n\\t\"\n        \"adds r8, r1 \\n\\t\"\n        \"adcs r9, r14 \\n\\t\"\n        \"adc r10, #0 \\n\\t\"\n        \"adds r8, r8 \\n\\t\"\n        \"adcs r9, r9 \\n\\t\"\n        \"adc r10, r10 \\n\\t\"\n        \"umull r1, r14, r5, r5 \\n\\t\"\n        \"adds r8, r1 \\n\\t\"\n        \"adcs r9, r14 \\n\\t\"\n        \"adc r10, #0 \\n\\t\"\n        \"adds r8, r11 \\n\\t\"\n        \"adcs r9, r12 \\n\\t\"\n        \"adc r10, #0 \\n\\t\"\n        \"stmia r0!, {r8} \\n\\t\"\n\n        \"mov r12, #0 \\n\\t\"\n        \"umull r8, r11, r4, r7 \\n\\t\"\n        \"umull r1, r14, r5, r6 \\n\\t\"\n        \"adds r8, r1 \\n\\t\"\n        \"adcs r11, r14 \\n\\t\"\n        \"adc r12, #0 \\n\\t\"\n        \"adds r8, r8 \\n\\t\"\n        \"adcs r11, r11 \\n\\t\"\n        \"adc r12, r12 \\n\\t\"\n        \"adds r8, r9 \\n\\t\"\n        \"adcs r11, r10 \\n\\t\"\n        \"adc r12, #0 \\n\\t\"\n        \"stmia r0!, {r8} \\n\\t\"\n\n        \"mov r8, #0 \\n\\t\"\n        \"umull r1, r10, r5, r7 \\n\\t\"\n        \"adds r1, r1 \\n\\t\"\n        \"adcs r10, r10 \\n\\t\"\n        \"adc r8, #0 \\n\\t\"\n        \"adds r11, r1 \\n\\t\"\n        \"adcs r12, r10 \\n\\t\"\n        \"adc r8, #0 \\n\\t\"\n        \"umull r1, r10, r6, r6 \\n\\t\"\n        \"adds r11, r1 \\n\\t\"\n        \"adcs r12, r10 \\n\\t\"\n        \"adc r8, #0 \\n\\t\"\n        \"stmia r0!, {r11} \\n\\t\"\n\n        \"mov r11, #0 \\n\\t\"\n        \"umull r1, r10, r6, r7 \\n\\t\"\n        \"adds r1, r1 \\n\\t\"\n        \"adcs r10, r10 \\n\\t\"\n        \"adc r11, #0 \\n\\t\"\n        \"adds r12, r1 \\n\\t\"\n        \"adcs r8, r10 \\n\\t\"\n        \"adc r11, #0 \\n\\t\"\n        \"stmia r0!, {r12} \\n\\t\"\n\n        \"umull r1, r10, r7, r7 \\n\\t\"\n        \"adds r8, r1 \\n\\t\"\n        \"adcs r11, r10 \\n\\t\"\n        \"stmia r0!, {r8, r11} \\n\\t\"\n    #if (uECC_PLATFORM != uECC_arm_thumb2)\n        \".syntax divided \\n\\t\"\n    #endif\n        : \"+r\" (r0), \"+r\" (r1)\n        :\n        : \"r2\", \"r3\", \"r4\", \"r5\", \"r6\", \"r7\", \"r8\", \"r9\", \"r10\", \"r11\", \"r12\", \"r14\", \"cc\", \"memory\"\n    );\n}\n#define asm_square 1\n#endif /* (uECC_WORDS == 6) */\n\n#if (uECC_WORDS == 7)\nstatic void vli_square(uint32_t *result, const uint32_t *left) {\n    register uint32_t *r0 __asm__(\"r0\") = result;\n    register const uint32_t *r1 __asm__(\"r1\") = left;\n\n    __asm__ volatile (\n        \".syntax unified \\n\\t\"\n        \"ldmia r1!, {r2} \\n\\t\"\n        \"add r1, 20 \\n\\t\"\n        \"ldmia r1!, {r5} \\n\\t\"\n        \"add r0, 24 \\n\\t\"\n        \"umull r8, r9, r2, r5 \\n\\t\"\n        \"stmia r0!, {r8, r9} \\n\\t\"\n        \"sub r0, 32 \\n\\t\"\n        \"sub r1, 28 \\n\\t\"\n\n        \"ldmia r1!, {r2, r3, r4, r5, r6, r7} \\n\\t\"\n\n        \"umull r11, r12, r2, r2 \\n\\t\"\n        \"stmia r0!, {r11} \\n\\t\"\n\n        \"mov r9, #0 \\n\\t\"\n        \"umull r10, r11, r2, r3 \\n\\t\"\n        \"adds r12, r10 \\n\\t\"\n        \"adcs r8, r11, #0 \\n\\t\"\n        \"adc r9, #0 \\n\\t\"\n        \"adds r12, r10 \\n\\t\"\n        \"adcs r8, r11 \\n\\t\"\n        \"adc r9, #0 \\n\\t\"\n        \"stmia r0!, {r12} \\n\\t\"\n\n        \"mov r10, #0 \\n\\t\"\n        \"umull r11, r12, r2, r4 \\n\\t\"\n        \"adds r11, r11 \\n\\t\"\n        \"adcs r12, r12 \\n\\t\"\n        \"adc r10, #0 \\n\\t\"\n        \"adds r8, r11 \\n\\t\"\n        \"adcs r9, r12 \\n\\t\"\n        \"adc r10, #0 \\n\\t\"\n        \"umull r11, r12, r3, r3 \\n\\t\"\n        \"adds r8, r11 \\n\\t\"\n        \"adcs r9, r12 \\n\\t\"\n        \"adc r10, #0 \\n\\t\"\n        \"stmia r0!, {r8} \\n\\t\"\n\n        \"mov r12, #0 \\n\\t\"\n        \"umull r8, r11, r2, r5 \\n\\t\"\n        \"mov r14, r11 \\n\\t\"\n        \"umlal r8, r11, r3, r4 \\n\\t\"\n        \"cmp r14, r11 \\n\\t\"\n        \"it hi \\n\\t\"\n        \"adchi r12, #0 \\n\\t\"\n        \"adds r8, r8 \\n\\t\"\n        \"adcs r11, r11 \\n\\t\"\n        \"adc r12, r12 \\n\\t\"\n        \"adds r8, r9 \\n\\t\"\n        \"adcs r11, r10 \\n\\t\"\n        \"adc r12, #0 \\n\\t\"\n        \"stmia r0!, {r8} \\n\\t\"\n\n        \"mov r10, #0 \\n\\t\"\n        \"umull r8, r9, r2, r6 \\n\\t\"\n        \"mov r14, r9 \\n\\t\"\n        \"umlal r8, r9, r3, r5 \\n\\t\"\n        \"cmp r14, r9 \\n\\t\"\n        \"it hi \\n\\t\"\n        \"adchi r10, #0 \\n\\t\"\n        \"adds r8, r8 \\n\\t\"\n        \"adcs r9, r9 \\n\\t\"\n        \"adc r10, r10 \\n\\t\"\n        \"mov r14, r9 \\n\\t\"\n        \"umlal r8, r9, r4, r4 \\n\\t\"\n        \"cmp r14, r9 \\n\\t\"\n        \"it hi \\n\\t\"\n        \"adchi r10, #0 \\n\\t\"\n        \"adds r8, r11 \\n\\t\"\n        \"adcs r9, r12 \\n\\t\"\n        \"adc r10, #0 \\n\\t\"\n        \"stmia r0!, {r8} \\n\\t\"\n\n        \"mov r12, #0 \\n\\t\"\n        \"umull r8, r11, r2, r7 \\n\\t\"\n        \"mov r14, r11 \\n\\t\"\n        \"umlal r8, r11, r3, r6 \\n\\t\"\n        \"cmp r14, r11 \\n\\t\"\n        \"it hi \\n\\t\"\n        \"adchi r12, #0 \\n\\t\"\n        \"mov r14, r11 \\n\\t\"\n        \"umlal r8, r11, r4, r5 \\n\\t\"\n        \"cmp r14, r11 \\n\\t\"\n        \"it hi \\n\\t\"\n        \"adchi r12, #0 \\n\\t\"\n        \"adds r8, r8 \\n\\t\"\n        \"adcs r11, r11 \\n\\t\"\n        \"adc r12, r12 \\n\\t\"\n        \"adds r8, r9 \\n\\t\"\n        \"adcs r11, r10 \\n\\t\"\n        \"adc r12, #0 \\n\\t\"\n        \"stmia r0!, {r8} \\n\\t\"\n\n        \"ldmia r1!, {r2} \\n\\t\"\n        \"mov r10, #0 \\n\\t\"\n        \"umull r8, r9, r3, r7 \\n\\t\"\n        \"mov r14, r9 \\n\\t\"\n        \"umlal r8, r9, r4, r6 \\n\\t\"\n        \"cmp r14, r9 \\n\\t\"\n        \"it hi \\n\\t\"\n        \"adchi r10, #0 \\n\\t\"\n        \"ldr r14, [r0] \\n\\t\"\n        \"adds r8, r14 \\n\\t\"\n        \"adcs r9, #0 \\n\\t\"\n        \"adc r10, #0 \\n\\t\"\n        \"adds r8, r8 \\n\\t\"\n        \"adcs r9, r9 \\n\\t\"\n        \"adc r10, r10 \\n\\t\"\n        \"mov r14, r9 \\n\\t\"\n        \"umlal r8, r9, r5, r5 \\n\\t\"\n        \"cmp r14, r9 \\n\\t\"\n        \"it hi \\n\\t\"\n        \"adchi r10, #0 \\n\\t\"\n        \"adds r8, r11 \\n\\t\"\n        \"adcs r9, r12 \\n\\t\"\n        \"adc r10, #0 \\n\\t\"\n        \"stmia r0!, {r8} \\n\\t\"\n\n        \"mov r12, #0 \\n\\t\"\n        \"umull r8, r11, r3, r2 \\n\\t\"\n        \"mov r14, r11 \\n\\t\"\n        \"umlal r8, r11, r4, r7 \\n\\t\"\n        \"cmp r14, r11 \\n\\t\"\n        \"it hi \\n\\t\"\n        \"adchi r12, #0 \\n\\t\"\n        \"mov r14, r11 \\n\\t\"\n        \"umlal r8, r11, r5, r6 \\n\\t\"\n        \"cmp r14, r11 \\n\\t\"\n        \"it hi \\n\\t\"\n        \"adchi r12, #0 \\n\\t\"\n        \"ldr r14, [r0] \\n\\t\"\n        \"adds r8, r14 \\n\\t\"\n        \"adcs r11, #0 \\n\\t\"\n        \"adc r12, #0 \\n\\t\"\n        \"adds r8, r8 \\n\\t\"\n        \"adcs r11, r11 \\n\\t\"\n        \"adc r12, r12 \\n\\t\"\n        \"adds r8, r9 \\n\\t\"\n        \"adcs r11, r10 \\n\\t\"\n        \"adc r12, #0 \\n\\t\"\n        \"stmia r0!, {r8} \\n\\t\"\n\n        \"mov r10, #0 \\n\\t\"\n        \"umull r8, r9, r4, r2 \\n\\t\"\n        \"mov r14, r9 \\n\\t\"\n        \"umlal r8, r9, r5, r7 \\n\\t\"\n        \"cmp r14, r9 \\n\\t\"\n        \"it hi \\n\\t\"\n        \"adchi r10, #0 \\n\\t\"\n        \"adds r8, r8 \\n\\t\"\n        \"adcs r9, r9 \\n\\t\"\n        \"adc r10, r10 \\n\\t\"\n        \"mov r14, r9 \\n\\t\"\n        \"umlal r8, r9, r6, r6 \\n\\t\"\n        \"cmp r14, r9 \\n\\t\"\n        \"it hi \\n\\t\"\n        \"adchi r10, #0 \\n\\t\"\n        \"adds r8, r11 \\n\\t\"\n        \"adcs r9, r12 \\n\\t\"\n        \"adc r10, #0 \\n\\t\"\n        \"stmia r0!, {r8} \\n\\t\"\n\n        \"mov r12, #0 \\n\\t\"\n        \"umull r8, r11, r5, r2 \\n\\t\"\n        \"mov r14, r11 \\n\\t\"\n        \"umlal r8, r11, r6, r7 \\n\\t\"\n        \"cmp r14, r11 \\n\\t\"\n        \"it hi \\n\\t\"\n        \"adchi r12, #0 \\n\\t\"\n        \"adds r8, r8 \\n\\t\"\n        \"adcs r11, r11 \\n\\t\"\n        \"adc r12, r12 \\n\\t\"\n        \"adds r8, r9 \\n\\t\"\n        \"adcs r11, r10 \\n\\t\"\n        \"adc r12, #0 \\n\\t\"\n        \"stmia r0!, {r8} \\n\\t\"\n\n        \"mov r8, #0 \\n\\t\"\n        \"umull r1, r10, r6, r2 \\n\\t\"\n        \"adds r1, r1 \\n\\t\"\n        \"adcs r10, r10 \\n\\t\"\n        \"adc r8, #0 \\n\\t\"\n        \"adds r11, r1 \\n\\t\"\n        \"adcs r12, r10 \\n\\t\"\n        \"adc r8, #0 \\n\\t\"\n        \"umull r1, r10, r7, r7 \\n\\t\"\n        \"adds r11, r1 \\n\\t\"\n        \"adcs r12, r10 \\n\\t\"\n        \"adc r8, #0 \\n\\t\"\n        \"stmia r0!, {r11} \\n\\t\"\n\n        \"mov r11, #0 \\n\\t\"\n        \"umull r1, r10, r7, r2 \\n\\t\"\n        \"adds r1, r1 \\n\\t\"\n        \"adcs r10, r10 \\n\\t\"\n        \"adc r11, #0 \\n\\t\"\n        \"adds r12, r1 \\n\\t\"\n        \"adcs r8, r10 \\n\\t\"\n        \"adc r11, #0 \\n\\t\"\n        \"stmia r0!, {r12} \\n\\t\"\n\n        \"umull r1, r10, r2, r2 \\n\\t\"\n        \"adds r8, r1 \\n\\t\"\n        \"adcs r11, r10 \\n\\t\"\n        \"stmia r0!, {r8, r11} \\n\\t\"\n    #if (uECC_PLATFORM != uECC_arm_thumb2)\n        \".syntax divided \\n\\t\"\n    #endif\n        : \"+r\" (r0), \"+r\" (r1)\n        :\n        : \"r2\", \"r3\", \"r4\", \"r5\", \"r6\", \"r7\", \"r8\", \"r9\", \"r10\", \"r11\", \"r12\", \"r14\", \"cc\", \"memory\"\n    );\n}\n#define asm_square 1\n#endif /* (uECC_WORDS == 7) */\n\n#if (uECC_WORDS == 8)\nstatic void vli_square(uint32_t *result, const uint32_t *left) {\n    register uint32_t *r0 __asm__(\"r0\") = result;\n    register const uint32_t *r1 __asm__(\"r1\") = left;\n\n    __asm__ volatile (\n        \".syntax unified \\n\\t\"\n        \"ldmia r1!, {r2, r3} \\n\\t\"\n        \"add r1, 16 \\n\\t\"\n        \"ldmia r1!, {r5, r6} \\n\\t\"\n        \"add r0, 24 \\n\\t\"\n\n        \"umull r8, r9, r2, r5 \\n\\t\"\n        \"stmia r0!, {r8} \\n\\t\"\n\n        \"umull r12, r10, r2, r6 \\n\\t\"\n        \"adds r9, r12 \\n\\t\"\n        \"adc r10, #0 \\n\\t\"\n        \"stmia r0!, {r9} \\n\\t\"\n\n        \"umull r8, r9, r3, r6 \\n\\t\"\n        \"adds r10, r8 \\n\\t\"\n        \"adc r11, r9, #0 \\n\\t\"\n        \"stmia r0!, {r10, r11} \\n\\t\"\n\n        \"sub r0, 40 \\n\\t\"\n        \"sub r1, 32 \\n\\t\"\n        \"ldmia r1!, {r2,r3,r4,r5,r6,r7} \\n\\t\"\n\n        \"umull r11, r12, r2, r2 \\n\\t\"\n        \"stmia r0!, {r11} \\n\\t\"\n\n        \"mov r9, #0 \\n\\t\"\n        \"umull r10, r11, r2, r3 \\n\\t\"\n        \"adds r12, r10 \\n\\t\"\n        \"adcs r8, r11, #0 \\n\\t\"\n        \"adc r9, #0 \\n\\t\"\n        \"adds r12, r10 \\n\\t\"\n        \"adcs r8, r11 \\n\\t\"\n        \"adc r9, #0 \\n\\t\"\n        \"stmia r0!, {r12} \\n\\t\"\n\n        \"mov r10, #0 \\n\\t\"\n        \"umull r11, r12, r2, r4 \\n\\t\"\n        \"adds r11, r11 \\n\\t\"\n        \"adcs r12, r12 \\n\\t\"\n        \"adc r10, #0 \\n\\t\"\n        \"adds r8, r11 \\n\\t\"\n        \"adcs r9, r12 \\n\\t\"\n        \"adc r10, #0 \\n\\t\"\n        \"umull r11, r12, r3, r3 \\n\\t\"\n        \"adds r8, r11 \\n\\t\"\n        \"adcs r9, r12 \\n\\t\"\n        \"adc r10, #0 \\n\\t\"\n        \"stmia r0!, {r8} \\n\\t\"\n\n        \"mov r12, #0 \\n\\t\"\n        \"umull r8, r11, r2, r5 \\n\\t\"\n        \"mov r14, r11 \\n\\t\"\n        \"umlal r8, r11, r3, r4 \\n\\t\"\n        \"cmp r14, r11 \\n\\t\"\n        \"it hi \\n\\t\"\n        \"adchi r12, #0 \\n\\t\"\n        \"adds r8, r8 \\n\\t\"\n        \"adcs r11, r11 \\n\\t\"\n        \"adc r12, r12 \\n\\t\"\n        \"adds r8, r9 \\n\\t\"\n        \"adcs r11, r10 \\n\\t\"\n        \"adc r12, #0 \\n\\t\"\n        \"stmia r0!, {r8} \\n\\t\"\n\n        \"mov r10, #0 \\n\\t\"\n        \"umull r8, r9, r2, r6 \\n\\t\"\n        \"mov r14, r9 \\n\\t\"\n        \"umlal r8, r9, r3, r5 \\n\\t\"\n        \"cmp r14, r9 \\n\\t\"\n        \"it hi \\n\\t\"\n        \"adchi r10, #0 \\n\\t\"\n        \"adds r8, r8 \\n\\t\"\n        \"adcs r9, r9 \\n\\t\"\n        \"adc r10, r10 \\n\\t\"\n        \"mov r14, r9 \\n\\t\"\n        \"umlal r8, r9, r4, r4 \\n\\t\"\n        \"cmp r14, r9 \\n\\t\"\n        \"it hi \\n\\t\"\n        \"adchi r10, #0 \\n\\t\"\n        \"adds r8, r11 \\n\\t\"\n        \"adcs r9, r12 \\n\\t\"\n        \"adc r10, #0 \\n\\t\"\n        \"stmia r0!, {r8} \\n\\t\"\n\n        \"mov r12, #0 \\n\\t\"\n        \"umull r8, r11, r2, r7 \\n\\t\"\n        \"mov r14, r11 \\n\\t\"\n        \"umlal r8, r11, r3, r6 \\n\\t\"\n        \"cmp r14, r11 \\n\\t\"\n        \"it hi \\n\\t\"\n        \"adchi r12, #0 \\n\\t\"\n        \"mov r14, r11 \\n\\t\"\n        \"umlal r8, r11, r4, r5 \\n\\t\"\n        \"cmp r14, r11 \\n\\t\"\n        \"it hi \\n\\t\"\n        \"adchi r12, #0 \\n\\t\"\n        \"adds r8, r8 \\n\\t\"\n        \"adcs r11, r11 \\n\\t\"\n        \"adc r12, r12 \\n\\t\"\n        \"adds r8, r9 \\n\\t\"\n        \"adcs r11, r10 \\n\\t\"\n        \"adc r12, #0 \\n\\t\"\n        \"stmia r0!, {r8} \\n\\t\"\n\n        \"ldmia r1!, {r2} \\n\\t\"\n        \"mov r10, #0 \\n\\t\"\n        \"umull r8, r9, r3, r7 \\n\\t\"\n        \"mov r14, r9 \\n\\t\"\n        \"umlal r8, r9, r4, r6 \\n\\t\"\n        \"cmp r14, r9 \\n\\t\"\n        \"it hi \\n\\t\"\n        \"adchi r10, #0 \\n\\t\"\n        \"ldr r14, [r0] \\n\\t\"\n        \"adds r8, r14 \\n\\t\"\n        \"adcs r9, #0 \\n\\t\"\n        \"adc r10, #0 \\n\\t\"\n        \"adds r8, r8 \\n\\t\"\n        \"adcs r9, r9 \\n\\t\"\n        \"adc r10, r10 \\n\\t\"\n        \"mov r14, r9 \\n\\t\"\n        \"umlal r8, r9, r5, r5 \\n\\t\"\n        \"cmp r14, r9 \\n\\t\"\n        \"it hi \\n\\t\"\n        \"adchi r10, #0 \\n\\t\"\n        \"adds r8, r11 \\n\\t\"\n        \"adcs r9, r12 \\n\\t\"\n        \"adc r10, #0 \\n\\t\"\n        \"stmia r0!, {r8} \\n\\t\"\n\n        \"mov r12, #0 \\n\\t\"\n        \"umull r8, r11, r3, r2 \\n\\t\"\n        \"mov r14, r11 \\n\\t\"\n        \"umlal r8, r11, r4, r7 \\n\\t\"\n        \"cmp r14, r11 \\n\\t\"\n        \"it hi \\n\\t\"\n        \"adchi r12, #0 \\n\\t\"\n        \"mov r14, r11 \\n\\t\"\n        \"umlal r8, r11, r5, r6 \\n\\t\"\n        \"cmp r14, r11 \\n\\t\"\n        \"it hi \\n\\t\"\n        \"adchi r12, #0 \\n\\t\"\n        \"ldr r14, [r0] \\n\\t\"\n        \"adds r8, r14 \\n\\t\"\n        \"adcs r11, #0 \\n\\t\"\n        \"adc r12, #0 \\n\\t\"\n        \"adds r8, r8 \\n\\t\"\n        \"adcs r11, r11 \\n\\t\"\n        \"adc r12, r12 \\n\\t\"\n        \"adds r8, r9 \\n\\t\"\n        \"adcs r11, r10 \\n\\t\"\n        \"adc r12, #0 \\n\\t\"\n        \"stmia r0!, {r8} \\n\\t\"\n\n        \"ldmia r1!, {r3} \\n\\t\"\n        \"mov r10, #0 \\n\\t\"\n        \"umull r8, r9, r4, r2 \\n\\t\"\n        \"mov r14, r9 \\n\\t\"\n        \"umlal r8, r9, r5, r7 \\n\\t\"\n        \"cmp r14, r9 \\n\\t\"\n        \"it hi \\n\\t\"\n        \"adchi r10, #0 \\n\\t\"\n        \"ldr r14, [r0] \\n\\t\"\n        \"adds r8, r14 \\n\\t\"\n        \"adcs r9, #0 \\n\\t\"\n        \"adc r10, #0 \\n\\t\"\n        \"adds r8, r8 \\n\\t\"\n        \"adcs r9, r9 \\n\\t\"\n        \"adc r10, r10 \\n\\t\"\n        \"mov r14, r9 \\n\\t\"\n        \"umlal r8, r9, r6, r6 \\n\\t\"\n        \"cmp r14, r9 \\n\\t\"\n        \"it hi \\n\\t\"\n        \"adchi r10, #0 \\n\\t\"\n        \"adds r8, r11 \\n\\t\"\n        \"adcs r9, r12 \\n\\t\"\n        \"adc r10, #0 \\n\\t\"\n        \"stmia r0!, {r8} \\n\\t\"\n\n        \"mov r12, #0 \\n\\t\"\n        \"umull r8, r11, r4, r3 \\n\\t\"\n        \"mov r14, r11 \\n\\t\"\n        \"umlal r8, r11, r5, r2 \\n\\t\"\n        \"cmp r14, r11 \\n\\t\"\n        \"it hi \\n\\t\"\n        \"adchi r12, #0 \\n\\t\"\n        \"mov r14, r11 \\n\\t\"\n        \"umlal r8, r11, r6, r7 \\n\\t\"\n        \"cmp r14, r11 \\n\\t\"\n        \"it hi \\n\\t\"\n        \"adchi r12, #0 \\n\\t\"\n        \"ldr r14, [r0] \\n\\t\"\n        \"adds r8, r14 \\n\\t\"\n        \"adcs r11, #0 \\n\\t\"\n        \"adc r12, #0 \\n\\t\"\n        \"adds r8, r8 \\n\\t\"\n        \"adcs r11, r11 \\n\\t\"\n        \"adc r12, r12 \\n\\t\"\n        \"adds r8, r9 \\n\\t\"\n        \"adcs r11, r10 \\n\\t\"\n        \"adc r12, #0 \\n\\t\"\n        \"stmia r0!, {r8} \\n\\t\"\n\n        \"mov r10, #0 \\n\\t\"\n        \"umull r8, r9, r5, r3 \\n\\t\"\n        \"mov r14, r9 \\n\\t\"\n        \"umlal r8, r9, r6, r2 \\n\\t\"\n        \"cmp r14, r9 \\n\\t\"\n        \"it hi \\n\\t\"\n        \"adchi r10, #0 \\n\\t\"\n        \"adds r8, r8 \\n\\t\"\n        \"adcs r9, r9 \\n\\t\"\n        \"adc r10, r10 \\n\\t\"\n        \"mov r14, r9 \\n\\t\"\n        \"umlal r8, r9, r7, r7 \\n\\t\"\n        \"cmp r14, r9 \\n\\t\"\n        \"it hi \\n\\t\"\n        \"adchi r10, #0 \\n\\t\"\n        \"adds r8, r11 \\n\\t\"\n        \"adcs r9, r12 \\n\\t\"\n        \"adc r10, #0 \\n\\t\"\n        \"stmia r0!, {r8} \\n\\t\"\n\n        \"mov r12, #0 \\n\\t\"\n        \"umull r8, r11, r6, r3 \\n\\t\"\n        \"mov r14, r11 \\n\\t\"\n        \"umlal r8, r11, r7, r2 \\n\\t\"\n        \"cmp r14, r11 \\n\\t\"\n        \"it hi \\n\\t\"\n        \"adchi r12, #0 \\n\\t\"\n        \"adds r8, r8 \\n\\t\"\n        \"adcs r11, r11 \\n\\t\"\n        \"adc r12, r12 \\n\\t\"\n        \"adds r8, r9 \\n\\t\"\n        \"adcs r11, r10 \\n\\t\"\n        \"adc r12, #0 \\n\\t\"\n        \"stmia r0!, {r8} \\n\\t\"\n\n        \"mov r8, #0 \\n\\t\"\n        \"umull r1, r10, r7, r3 \\n\\t\"\n        \"adds r1, r1 \\n\\t\"\n        \"adcs r10, r10 \\n\\t\"\n        \"adc r8, #0 \\n\\t\"\n        \"adds r11, r1 \\n\\t\"\n        \"adcs r12, r10 \\n\\t\"\n        \"adc r8, #0 \\n\\t\"\n        \"umull r1, r10, r2, r2 \\n\\t\"\n        \"adds r11, r1 \\n\\t\"\n        \"adcs r12, r10 \\n\\t\"\n        \"adc r8, #0 \\n\\t\"\n        \"stmia r0!, {r11} \\n\\t\"\n\n        \"mov r11, #0 \\n\\t\"\n        \"umull r1, r10, r2, r3 \\n\\t\"\n        \"adds r1, r1 \\n\\t\"\n        \"adcs r10, r10 \\n\\t\"\n        \"adc r11, #0 \\n\\t\"\n        \"adds r12, r1 \\n\\t\"\n        \"adcs r8, r10 \\n\\t\"\n        \"adc r11, #0 \\n\\t\"\n        \"stmia r0!, {r12} \\n\\t\"\n\n        \"umull r1, r10, r3, r3 \\n\\t\"\n        \"adds r8, r1 \\n\\t\"\n        \"adcs r11, r10 \\n\\t\"\n        \"stmia r0!, {r8, r11} \\n\\t\"\n    #if (uECC_PLATFORM != uECC_arm_thumb2)\n        \".syntax divided \\n\\t\"\n    #endif\n        : \"+r\" (r0), \"+r\" (r1)\n        :\n        : \"r2\", \"r3\", \"r4\", \"r5\", \"r6\", \"r7\", \"r8\", \"r9\", \"r10\", \"r11\", \"r12\", \"r14\", \"cc\", \"memory\"\n    );\n}\n#define asm_square 1\n#endif /* (uECC_WORDS == 8) */\n#endif /* uECC_SQUARE_FUNC */\n\n#endif /* (uECC_PLATFORM != uECC_arm_thumb) */\n#endif /* (uECC_ASM == uECC_asm_fast) */\n\n#if !asm_add\nstatic uint32_t vli_add(uint32_t *result, const uint32_t *left, const uint32_t *right) {\n    uint32_t counter = uECC_WORDS;\n    uint32_t carry = 0;\n    uint32_t left_word;\n    uint32_t right_word;\n\n    __asm__ volatile (\n        \".syntax unified \\n\\t\"\n        \"1: \\n\\t\"\n        \"ldmia %[lptr]!, {%[left]} \\n\\t\"  /* Load left word. */\n        \"ldmia %[rptr]!, {%[right]} \\n\\t\" /* Load right word. */\n        \"lsrs %[carry], #1 \\n\\t\"          /* Set up carry flag (carry = 0 after this). */\n        \"adcs %[left], %[right] \\n\\t\"     /* Add with carry. */\n        \"adcs %[carry], %[carry] \\n\\t\"    /* Store carry bit. */\n        \"stmia %[dptr]!, {%[left]} \\n\\t\"  /* Store result word. */\n        \"subs %[ctr], #1 \\n\\t\"            /* Decrement counter. */\n        \"bne 1b \\n\\t\"                     /* Loop until counter == 0. */\n    #if (uECC_PLATFORM != uECC_arm_thumb2)\n        \".syntax divided \\n\\t\"\n    #endif\n    #if (uECC_PLATFORM == uECC_arm_thumb)\n        : [dptr] \"+l\" (result), [lptr] \"+l\" (left), [rptr] \"+l\" (right),\n          [ctr] \"+l\" (counter), [carry] \"+l\" (carry),\n          [left] \"=l\" (left_word), [right] \"=l\" (right_word)\n    #else\n        : [dptr] \"+r\" (result), [lptr] \"+r\" (left), [rptr] \"+r\" (right),\n          [ctr] \"+r\" (counter), [carry] \"+r\" (carry),\n          [left] \"=r\" (left_word), [right] \"=r\" (right_word)\n    #endif\n        :\n        : \"cc\", \"memory\"\n    );\n    return carry;\n}\n#define asm_add 1\n#endif\n\n#if !asm_sub\nstatic uint32_t vli_sub(uint32_t *result, const uint32_t *left, const uint32_t *right) {\n    uint32_t counter = uECC_WORDS;\n    uint32_t carry = 1; /* carry = 1 initially (means don't borrow) */\n    uint32_t left_word;\n    uint32_t right_word;\n\n    __asm__ volatile (\n        \".syntax unified \\n\\t\"\n        \"1: \\n\\t\"\n        \"ldmia %[lptr]!, {%[left]} \\n\\t\"  /* Load left word. */\n        \"ldmia %[rptr]!, {%[right]} \\n\\t\" /* Load right word. */\n        \"lsrs %[carry], #1 \\n\\t\"          /* Set up carry flag (carry = 0 after this). */\n        \"sbcs %[left], %[right] \\n\\t\"     /* Subtract with borrow. */\n        \"adcs %[carry], %[carry] \\n\\t\"    /* Store carry bit. */\n        \"stmia %[dptr]!, {%[left]} \\n\\t\"  /* Store result word. */\n        \"subs %[ctr], #1 \\n\\t\"            /* Decrement counter. */\n        \"bne 1b \\n\\t\"                     /* Loop until counter == 0. */\n    #if (uECC_PLATFORM != uECC_arm_thumb2)\n        \".syntax divided \\n\\t\"\n    #endif\n    #if (uECC_PLATFORM == uECC_arm_thumb)\n        : [dptr] \"+l\" (result), [lptr] \"+l\" (left), [rptr] \"+l\" (right),\n          [ctr] \"+l\" (counter), [carry] \"+l\" (carry),\n          [left] \"=l\" (left_word), [right] \"=l\" (right_word)\n    #else\n        : [dptr] \"+r\" (result), [lptr] \"+r\" (left), [rptr] \"+r\" (right),\n          [ctr] \"+r\" (counter), [carry] \"+r\" (carry),\n          [left] \"=r\" (left_word), [right] \"=r\" (right_word)\n    #endif\n        :\n        : \"cc\", \"memory\"\n    );\n    return !carry;\n}\n#define asm_sub 1\n#endif\n\n#if !asm_mult\nstatic void vli_mult(uint32_t *result, const uint32_t *left, const uint32_t *right) {\n#if (uECC_PLATFORM != uECC_arm_thumb)\n    uint32_t c0 = 0;\n    uint32_t c1 = 0;\n    uint32_t c2 = 0;\n    uint32_t k = 0;\n    uint32_t i;\n    uint32_t t0, t1;\n\n    __asm__ volatile (\n        \".syntax unified \\n\\t\"\n\n        \"1: \\n\\t\" /* outer loop (k < uECC_WORDS) */\n        \"movs %[i], #0 \\n\\t\" /* i = 0 */\n        \"b 3f \\n\\t\"\n\n        \"2: \\n\\t\" /* outer loop (k >= uECC_WORDS) */\n        \"movs %[i], %[k] \\n\\t\"      /* i = k */\n        \"subs %[i], %[eccdm1] \\n\\t\" /* i = k - (uECC_WORDS - 1) (times 4) */\n\n        \"3: \\n\\t\" /* inner loop */\n        \"subs %[t0], %[k], %[i] \\n\\t\" /* t0 = k-i */\n\n        \"ldr %[t1], [%[right], %[t0]] \\n\\t\" /* t1 = right[k - i] */\n        \"ldr %[t0], [%[left], %[i]] \\n\\t\"   /* t0 = left[i] */\n\n        \"umull %[t0], %[t1], %[t0], %[t1] \\n\\t\" /* (t0, t1) = left[i] * right[k - i] */\n\n        \"adds %[c0], %[t0] \\n\\t\" /* add low word to c0 */\n        \"adcs %[c1], %[t1] \\n\\t\" /* add high word to c1, including carry */\n        \"adcs %[c2], #0 \\n\\t\"    /* add carry to c2 */\n\n        \"adds %[i], #4 \\n\\t\"     /* i += 4 */\n        \"cmp %[i], %[eccd] \\n\\t\" /* i < uECC_WORDS (times 4)? */\n        \"bge 4f \\n\\t\"            /*   if not, exit the loop */\n        \"cmp %[i], %[k] \\n\\t\"    /* i <= k? */\n        \"ble 3b \\n\\t\"            /*   if so, continue looping */\n\n        \"4: \\n\\t\" /* end inner loop */\n\n        \"str %[c0], [%[result], %[k]] \\n\\t\" /* result[k] = c0 */\n        \"mov %[c0], %[c1] \\n\\t\"     /* c0 = c1 */\n        \"mov %[c1], %[c2] \\n\\t\"     /* c1 = c2 */\n        \"movs %[c2], #0 \\n\\t\"       /* c2 = 0 */\n        \"adds %[k], #4 \\n\\t\"        /* k += 4 */\n        \"cmp %[k], %[eccd] \\n\\t\"    /* k < uECC_WORDS (times 4) ? */\n        \"blt 1b \\n\\t\"               /*   if not, loop back, start with i = 0 */\n        \"cmp %[k], %[eccd2m1] \\n\\t\" /* k < uECC_WORDS * 2 - 1 (times 4) ? */\n        \"blt 2b \\n\\t\"               /*   if not, loop back, start with i = (k + 1) - uECC_WORDS */\n        /* end outer loop */\n\n        \"str %[c0], [%[result], %[k]] \\n\\t\" /* result[uECC_WORDS * 2 - 1] = c0 */\n    #if (uECC_PLATFORM != uECC_arm_thumb2)\n        \".syntax divided \\n\\t\"\n    #endif\n        : [c0] \"+r\" (c0), [c1] \"+r\" (c1), [c2] \"+r\" (c2),\n          [k] \"+r\" (k), [i] \"=&r\" (i), [t0] \"=&r\" (t0), [t1] \"=&r\" (t1)\n        : [result] \"r\" (result), [left] \"r\" (left), [right] \"r\" (right),\n          [eccd] \"I\" (uECC_WORDS * 4), [eccdm1] \"I\" ((uECC_WORDS-1) * 4),\n          [eccd2m1] \"I\" ((uECC_WORDS * 2 - 1) * 4)\n        : \"cc\", \"memory\"\n    );\n\n#else /* Thumb-1 */\n\n    register uint32_t *r0 __asm__(\"r0\") = result;\n    register const uint32_t *r1 __asm__(\"r1\") = left;\n    register const uint32_t *r2 __asm__(\"r2\") = right;\n\n    __asm__ volatile (\n        \".syntax unified \\n\\t\"\n        \"movs r3, #0 \\n\\t\" /* c0 = 0 */\n        \"movs r4, #0 \\n\\t\" /* c1 = 0 */\n        \"movs r5, #0 \\n\\t\" /* c2 = 0 */\n        \"movs r6, #0 \\n\\t\" /* k = 0 */\n\n        \"push {r0} \\n\\t\" /* keep result on the stack */\n\n        \"1: \\n\\t\" /* outer loop (k < uECC_WORDS) */\n        \"movs r7, #0 \\n\\t\" /* r7 = i = 0 */\n        \"b 3f \\n\\t\"\n\n        \"2: \\n\\t\" /* outer loop (k >= uECC_WORDS) */\n        \"movs r7, r6 \\n\\t\"        /* r7 = k */\n        \"subs r7, %[eccdm1] \\n\\t\" /* r7 = i = k - (uECC_WORDS - 1) (times 4) */\n\n        \"3: \\n\\t\" /* inner loop */\n        \"push {r3, r4, r5, r6} \\n\\t\" /* push things, r3 (c0) is at the top of stack. */\n        \"subs r0, r6, r7 \\n\\t\"       /* r0 = k - i */\n\n        \"ldr r4, [r2, r0] \\n\\t\" /* r4 = right[k - i] */\n        \"ldr r0, [r1, r7] \\n\\t\" /* r0 = left[i] */\n\n        \"lsrs r3, r0, #16 \\n\\t\" /* r3 = a1 */\n        \"uxth r0, r0 \\n\\t\"      /* r0 = a0 */\n\n        \"lsrs r5, r4, #16 \\n\\t\" /* r5 = b1 */\n        \"uxth r4, r4 \\n\\t\"      /* r4 = b0 */\n\n        \"movs r6, r3 \\n\\t\"     /* r6 = a1 */\n        \"muls r6, r5, r6 \\n\\t\" /* r6 = a1 * b1 */\n        \"muls r3, r4, r3 \\n\\t\" /* r3 = b0 * a1 */\n        \"muls r5, r0, r5 \\n\\t\" /* r5 = a0 * b1 */\n        \"muls r0, r4, r0 \\n\\t\" /* r0 = a0 * b0 */\n\n        \"movs r4, #0 \\n\\t\"  /* r4 = 0 */\n        \"adds r3, r5 \\n\\t\"  /* r3 = b0 * a1 + a0 * b1 */\n        \"adcs r4, r4 \\n\\t\"  /* r4 = carry */\n        \"lsls r4, #16 \\n\\t\" /* r4 = carry << 16 */\n        \"adds r6, r4 \\n\\t\"  /* r6 = a1 * b1 + carry */\n\n        \"lsls r4, r3, #16 \\n\\t\" /* r4 = (b0 * a1 + a0 * b1) << 16 */\n        \"lsrs r3, #16 \\n\\t\"     /* r3 = (b0 * a1 + a0 * b1) >> 16 */\n        \"adds r0, r4 \\n\\t\"      /* r0 = low word = a0 * b0 + ((b0 * a1 + a0 * b1) << 16) */\n        \"adcs r6, r3 \\n\\t\"      /* r6 = high word = a1 * b1 + carry + ((b0 * a1 + a0 * b1) >> 16) */\n\n        \"pop {r3, r4, r5} \\n\\t\" /* r3 = c0, r4 = c1, r5 = c2 */\n        \"adds r3, r0 \\n\\t\"      /* add low word to c0 */\n        \"adcs r4, r6 \\n\\t\"      /* add high word to c1, including carry */\n        \"movs r0, #0 \\n\\t\"      /* r0 = 0 (does not affect carry bit) */\n        \"adcs r5, r0 \\n\\t\"      /* add carry to c2 */\n\n        \"pop {r6} \\n\\t\" /* r6 = k */\n\n        \"adds r7, #4 \\n\\t\"     /* i += 4 */\n        \"cmp r7, %[eccd] \\n\\t\" /* i < uECC_WORDS (times 4)? */\n        \"bge 4f \\n\\t\"          /*   if not, exit the loop */\n        \"cmp r7, r6 \\n\\t\"      /* i <= k? */\n        \"ble 3b \\n\\t\"          /*   if so, continue looping */\n\n        \"4: \\n\\t\" /* end inner loop */\n\n        \"ldr r0, [sp, #0] \\n\\t\" /* r0 = result */\n\n        \"str r3, [r0, r6] \\n\\t\"   /* result[k] = c0 */\n        \"mov r3, r4 \\n\\t\"         /* c0 = c1 */\n        \"mov r4, r5 \\n\\t\"         /* c1 = c2 */\n        \"movs r5, #0 \\n\\t\"        /* c2 = 0 */\n        \"adds r6, #4 \\n\\t\"        /* k += 4 */\n        \"cmp r6, %[eccd] \\n\\t\"    /* k < uECC_WORDS (times 4) ? */\n        \"blt 1b \\n\\t\"             /*   if not, loop back, start with i = 0 */\n        \"cmp r6, %[eccd2m1] \\n\\t\" /* k < uECC_WORDS * 2 - 1 (times 4) ? */\n        \"blt 2b \\n\\t\"             /*   if not, loop back, start with i = (k + 1) - uECC_WORDS */\n        /* end outer loop */\n\n        \"str r3, [r0, r6] \\n\\t\" /* result[uECC_WORDS * 2 - 1] = c0 */\n        \"pop {r0} \\n\\t\"         /* pop result off the stack */\n\n        \".syntax divided \\n\\t\"\n        :\n        : [r0] \"l\" (r0), [r1] \"l\" (r1), [r2] \"l\" (r2), [eccd] \"I\" (uECC_WORDS * 4), [eccdm1] \"I\" ((uECC_WORDS-1) * 4), [eccd2m1] \"I\" ((uECC_WORDS * 2 - 1) * 4)\n        : \"r3\", \"r4\", \"r5\", \"r6\", \"r7\", \"cc\", \"memory\"\n    );\n#endif\n}\n#define asm_mult 1\n#endif /* !asm_mult */\n\n#if uECC_SQUARE_FUNC\n#if !asm_square\nstatic void vli_square(uint32_t *result, const uint32_t *left) {\n#if (uECC_PLATFORM != uECC_arm_thumb)\n    uint32_t c0 = 0;\n    uint32_t c1 = 0;\n    uint32_t c2 = 0;\n    uint32_t k = 0;\n    uint32_t i, tt;\n    uint32_t t0, t1;\n\n    __asm__ volatile (\n        \".syntax unified \\n\\t\"\n\n        \"1: \\n\\t\" /* outer loop (k < uECC_WORDS) */\n        \"movs %[i], #0 \\n\\t\" /* i = 0 */\n        \"b 3f \\n\\t\"\n\n        \"2: \\n\\t\" /* outer loop (k >= uECC_WORDS) */\n        \"movs %[i], %[k] \\n\\t\"      /* i = k */\n        \"subs %[i], %[eccdm1] \\n\\t\" /* i = k - (uECC_WORDS - 1) (times 4) */\n\n        \"3: \\n\\t\" /* inner loop */\n        \"subs %[tt], %[k], %[i] \\n\\t\" /* tt = k-i */\n\n        \"ldr %[t1], [%[left], %[tt]] \\n\\t\" /* t1 = left[k - i] */\n        \"ldr %[t0], [%[left], %[i]] \\n\\t\"  /* t0 = left[i] */\n\n        \"umull %[t0], %[t1], %[t0], %[t1] \\n\\t\" /* (t0, t1) = left[i] * right[k - i] */\n\n        \"cmp %[i], %[tt] \\n\\t\" /* (i < k - i) ? */\n        \"bge 4f \\n\\t\"          /*   if i >= k - i, skip */\n        \"lsls %[t1], #1 \\n\\t\"  /* high word << 1 */\n        \"adc %[c2], #0 \\n\\t\"   /* add carry bit to c2 */\n        \"lsls %[t0], #1 \\n\\t\"  /* low word << 1 */\n        \"adc %[t1], #0 \\n\\t\"   /* add carry bit to high word */\n\n        \"4: \\n\\t\"\n\n        \"adds %[c0], %[t0] \\n\\t\" /* add low word to c0 */\n        \"adcs %[c1], %[t1] \\n\\t\" /* add high word to c1, including carry */\n        \"adc %[c2], #0 \\n\\t\"     /* add carry to c2 */\n\n        \"adds %[i], #4 \\n\\t\"          /* i += 4 */\n        \"cmp %[i], %[k] \\n\\t\"         /* i <= k? */\n        \"bge 5f \\n\\t\"                 /*   if not, exit the loop */\n        \"subs %[tt], %[k], %[i] \\n\\t\" /* tt = k - i */\n        \"cmp %[i], %[tt] \\n\\t\"        /* i <= k - i? */\n        \"ble 3b \\n\\t\"                 /*   if so, continue looping */\n\n        \"5: \\n\\t\" /* end inner loop */\n\n        \"str %[c0], [%[result], %[k]] \\n\\t\" /* result[k] = c0 */\n        \"mov %[c0], %[c1] \\n\\t\"     /* c0 = c1 */\n        \"mov %[c1], %[c2] \\n\\t\"     /* c1 = c2 */\n        \"movs %[c2], #0 \\n\\t\"       /* c2 = 0 */\n        \"adds %[k], #4 \\n\\t\"        /* k += 4 */\n        \"cmp %[k], %[eccd] \\n\\t\"    /* k < uECC_WORDS (times 4) ? */\n        \"blt 1b \\n\\t\"               /*   if not, loop back, start with i = 0 */\n        \"cmp %[k], %[eccd2m1] \\n\\t\" /* k < uECC_WORDS * 2 - 1 (times 4) ? */\n        \"blt 2b \\n\\t\"               /*   if not, loop back, start with i = (k + 1) - uECC_WORDS */\n        /* end outer loop */\n\n        \"str %[c0], [%[result], %[k]] \\n\\t\" /* result[uECC_WORDS * 2 - 1] = c0 */\n    #if (uECC_PLATFORM != uECC_arm_thumb2)\n        \".syntax divided \\n\\t\"\n    #endif\n        : [c0] \"+r\" (c0), [c1] \"+r\" (c1), [c2] \"+r\" (c2),\n          [k] \"+r\" (k), [i] \"=&r\" (i), [tt] \"=&r\" (tt), [t0] \"=&r\" (t0), [t1] \"=&r\" (t1)\n        : [result] \"r\" (result), [left] \"r\" (left),\n          [eccd] \"I\" (uECC_WORDS * 4), [eccdm1] \"I\" ((uECC_WORDS-1) * 4),\n          [eccd2m1] \"I\" ((uECC_WORDS * 2 - 1) * 4)\n        : \"cc\", \"memory\"\n    );\n\n#else\n\n    register uint32_t *r0 __asm__(\"r0\") = result;\n    register const uint32_t *r1 __asm__(\"r1\") = left;\n\n    __asm__ volatile (\n        \".syntax unified \\n\\t\"\n        \"movs r2, #0 \\n\\t\" /* c0 = 0 */\n        \"movs r3, #0 \\n\\t\" /* c1 = 0 */\n        \"movs r4, #0 \\n\\t\" /* c2 = 0 */\n        \"movs r5, #0 \\n\\t\" /* k = 0 */\n\n        \"push {r0} \\n\\t\" /* keep result on the stack */\n\n        \"1: \\n\\t\" /* outer loop (k < uECC_WORDS) */\n        \"movs r6, #0 \\n\\t\" /* r6 = i = 0 */\n        \"b 3f \\n\\t\"\n\n        \"2: \\n\\t\" /* outer loop (k >= uECC_WORDS) */\n        \"movs r6, r5 \\n\\t\"        /* r6 = k */\n        \"subs r6, %[eccdm1] \\n\\t\" /* r6 = i = k - (uECC_WORDS - 1) (times 4) */\n\n        \"3: \\n\\t\" /* inner loop */\n        \"push {r2, r3, r4, r5} \\n\\t\" /* push things, r2 (c0) is at the top of stack. */\n        \"subs r7, r5, r6 \\n\\t\"       /* r7 = k - i */\n\n        \"ldr r3, [r1, r7] \\n\\t\" /* r3 = left[k - i] */\n        \"ldr r0, [r1, r6] \\n\\t\" /* r0 = left[i] */\n\n        \"lsrs r2, r0, #16 \\n\\t\" /* r2 = a1 */\n        \"uxth r0, r0 \\n\\t\"      /* r0 = a0 */\n\n        \"lsrs r4, r3, #16 \\n\\t\" /* r4 = b1 */\n        \"uxth r3, r3 \\n\\t\"      /* r3 = b0 */\n\n        \"movs r5, r2 \\n\\t\"     /* r5 = a1 */\n        \"muls r5, r4, r5 \\n\\t\" /* r5 = a1 * b1 */\n        \"muls r2, r3, r2 \\n\\t\" /* r2 = b0 * a1 */\n        \"muls r4, r0, r4 \\n\\t\" /* r4 = a0 * b1 */\n        \"muls r0, r3, r0 \\n\\t\" /* r0 = a0 * b0 */\n\n        \"movs r3, #0 \\n\\t\"  /* r3 = 0 */\n        \"adds r2, r4 \\n\\t\"  /* r2 = b0 * a1 + a0 * b1 */\n        \"adcs r3, r3 \\n\\t\"  /* r3 = carry */\n        \"lsls r3, #16 \\n\\t\" /* r3 = carry << 16 */\n        \"adds r5, r3 \\n\\t\"  /* r5 = a1 * b1 + carry */\n\n        \"lsls r3, r2, #16 \\n\\t\" /* r3 = (b0 * a1 + a0 * b1) << 16 */\n        \"lsrs r2, #16 \\n\\t\"     /* r2 = (b0 * a1 + a0 * b1) >> 16 */\n        \"adds r0, r3 \\n\\t\"      /* r0 = low word = a0 * b0 + ((b0 * a1 + a0 * b1) << 16) */\n        \"adcs r5, r2 \\n\\t\"      /* r5 = high word = a1 * b1 + carry + ((b0 * a1 + a0 * b1) >> 16) */\n\n        \"movs r3, #0 \\n\\t\"  /* r3 = 0 */\n        \"cmp r6, r7 \\n\\t\"   /* (i < k - i) ? */\n        \"mov r7, r3 \\n\\t\"   /* r7 = 0 (does not affect condition)*/\n        \"bge 4f \\n\\t\"       /*   if i >= k - i, skip */\n        \"lsls r5, #1 \\n\\t\"  /* high word << 1 */\n        \"adcs r7, r3 \\n\\t\"  /* r7 = carry bit for c2 */\n        \"lsls r0, #1 \\n\\t\"  /* low word << 1 */\n        \"adcs r5, r3 \\n\\t\"  /* add carry from shift to high word */\n\n        \"4: \\n\\t\"\n        \"pop {r2, r3, r4} \\n\\t\" /* r2 = c0, r3 = c1, r4 = c2 */\n        \"adds r2, r0 \\n\\t\"      /* add low word to c0 */\n        \"adcs r3, r5 \\n\\t\"      /* add high word to c1, including carry */\n        \"movs r0, #0 \\n\\t\"      /* r0 = 0 (does not affect carry bit) */\n        \"adcs r4, r0 \\n\\t\"      /* add carry to c2 */\n        \"adds r4, r7 \\n\\t\"      /* add carry from doubling (if any) */\n\n        \"pop {r5} \\n\\t\" /* r5 = k */\n\n        \"adds r6, #4 \\n\\t\"     /* i += 4 */\n        \"cmp r6, r5 \\n\\t\"      /* i <= k? */\n        \"bge 5f \\n\\t\"          /*   if not, exit the loop */\n        \"subs r7, r5, r6 \\n\\t\" /* r7 = k - i */\n        \"cmp r6, r7 \\n\\t\"      /* i <= k - i? */\n        \"ble 3b \\n\\t\"          /*   if so, continue looping */\n\n        \"5: \\n\\t\" /* end inner loop */\n\n        \"ldr r0, [sp, #0] \\n\\t\" /* r0 = result */\n\n        \"str r2, [r0, r5] \\n\\t\"   /* result[k] = c0 */\n        \"mov r2, r3 \\n\\t\"         /* c0 = c1 */\n        \"mov r3, r4 \\n\\t\"         /* c1 = c2 */\n        \"movs r4, #0 \\n\\t\"        /* c2 = 0 */\n        \"adds r5, #4 \\n\\t\"        /* k += 4 */\n        \"cmp r5, %[eccd] \\n\\t\"    /* k < uECC_WORDS (times 4) ? */\n        \"blt 1b \\n\\t\"             /*   if not, loop back, start with i = 0 */\n        \"cmp r5, %[eccd2m1] \\n\\t\" /* k < uECC_WORDS * 2 - 1 (times 4) ? */\n        \"blt 2b \\n\\t\"             /*   if not, loop back, start with i = (k + 1) - uECC_WORDS */\n        /* end outer loop */\n\n        \"str r2, [r0, r5] \\n\\t\" /* result[uECC_WORDS * 2 - 1] = c0 */\n        \"pop {r0} \\n\\t\"        /* pop result off the stack */\n\n        \".syntax divided \\n\\t\"\n        : [r0] \"+l\" (r0), [r1] \"+l\" (r1)\n        : [eccd] \"I\" (uECC_WORDS * 4), [eccdm1] \"I\" ((uECC_WORDS-1) * 4),\n          [eccd2m1] \"I\" ((uECC_WORDS * 2 - 1) * 4)\n        : \"r2\", \"r3\", \"r4\", \"r5\", \"r6\", \"r7\", \"cc\", \"memory\"\n    );\n#endif\n}\n#define asm_square 1\n#endif /* !asm_square */\n#endif /* uECC_SQUARE_FUNC */"
  },
  {
    "path": "bluetoe/bindings/nordic/uECC/uECC.c",
    "content": "/* Copyright 2014, Kenneth MacKay. Licensed under the BSD 2-clause license. */\n\n#include \"uECC.h\"\n\n#ifndef uECC_PLATFORM\n    #if __AVR__\n        #define uECC_PLATFORM uECC_avr\n    #elif defined(__thumb2__) || defined(_M_ARMT) /* I think MSVC only supports Thumb-2 targets */\n        #define uECC_PLATFORM uECC_arm_thumb2\n    #elif defined(__thumb__)\n        #define uECC_PLATFORM uECC_arm_thumb\n    #elif defined(__arm__) || defined(_M_ARM)\n        #define uECC_PLATFORM uECC_arm\n    #elif defined(__i386__) || defined(_M_IX86) || defined(_X86_) || defined(__I86__)\n        #define uECC_PLATFORM uECC_x86\n    #elif defined(__amd64__) || defined(_M_X64)\n        #define uECC_PLATFORM uECC_x86_64\n    #else\n        #define uECC_PLATFORM uECC_arch_other\n    #endif\n#endif\n\n#ifndef uECC_WORD_SIZE\n    #if uECC_PLATFORM == uECC_avr\n        #define uECC_WORD_SIZE 1\n    #elif (uECC_PLATFORM == uECC_x86_64)\n        #define uECC_WORD_SIZE 8\n    #else\n        #define uECC_WORD_SIZE 4\n    #endif\n#endif\n\n#if (uECC_CURVE == uECC_secp160r1 || uECC_CURVE == uECC_secp224r1) && (uECC_WORD_SIZE == 8)\n    #undef uECC_WORD_SIZE\n    #define uECC_WORD_SIZE 4\n    #if (uECC_PLATFORM == uECC_x86_64)\n        #undef uECC_PLATFORM\n        #define uECC_PLATFORM uECC_x86\n    #endif\n#endif\n\n#if (uECC_WORD_SIZE != 1) && (uECC_WORD_SIZE != 4) && (uECC_WORD_SIZE != 8)\n    #error \"Unsupported value for uECC_WORD_SIZE\"\n#endif\n\n#if (uECC_ASM && (uECC_PLATFORM == uECC_avr) && (uECC_WORD_SIZE != 1))\n    #pragma message (\"uECC_WORD_SIZE must be 1 when using AVR asm\")\n    #undef uECC_WORD_SIZE\n    #define uECC_WORD_SIZE 1\n#endif\n\n#if (uECC_ASM && \\\n     (uECC_PLATFORM == uECC_arm || uECC_PLATFORM == uECC_arm_thumb) && \\\n     (uECC_WORD_SIZE != 4))\n    #pragma message (\"uECC_WORD_SIZE must be 4 when using ARM asm\")\n    #undef uECC_WORD_SIZE\n    #define uECC_WORD_SIZE 4\n#endif\n\n#if __STDC_VERSION__ >= 199901L\n    #define RESTRICT restrict\n#else\n    #define RESTRICT\n#endif\n\n#if defined(__SIZEOF_INT128__) || ((__clang_major__ * 100 + __clang_minor__) >= 302)\n    #define SUPPORTS_INT128 1\n#else\n    #define SUPPORTS_INT128 0\n#endif\n\n#define MAX_TRIES 64\n\n#if (uECC_WORD_SIZE == 1)\n\ntypedef uint8_t uECC_word_t;\ntypedef uint16_t uECC_dword_t;\ntypedef uint8_t wordcount_t;\ntypedef int8_t swordcount_t;\ntypedef int16_t bitcount_t;\ntypedef int8_t cmpresult_t;\n\n#define HIGH_BIT_SET 0x80\n#define uECC_WORD_BITS 8\n#define uECC_WORD_BITS_SHIFT 3\n#define uECC_WORD_BITS_MASK 0x07\n\n#define uECC_WORDS_1 20\n#define uECC_WORDS_2 24\n#define uECC_WORDS_3 32\n#define uECC_WORDS_4 32\n#define uECC_WORDS_5 28\n\n#define uECC_N_WORDS_1 21\n#define uECC_N_WORDS_2 24\n#define uECC_N_WORDS_3 32\n#define uECC_N_WORDS_4 32\n#define uECC_N_WORDS_5 28\n\n#define Curve_P_1 {0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, \\\n                   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \\\n                   0xFF, 0xFF, 0xFF, 0xFF}\n#define Curve_P_2 {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \\\n                   0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \\\n                   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}\n#define Curve_P_3 {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \\\n                   0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, \\\n                   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \\\n                   0x01, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF}\n#define Curve_P_4 {0x2F, 0xFC, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, \\\n                   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \\\n                   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \\\n                   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}\n#define Curve_P_5 {0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \\\n                   0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, \\\n                   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \\\n                   0xFF, 0xFF, 0xFF, 0xFF}\n\n#define Curve_B_1 {0x45, 0xFA, 0x65, 0xC5, 0xAD, 0xD4, 0xD4, 0x81, \\\n                   0x9F, 0xF8, 0xAC, 0x65, 0x8B, 0x7A, 0xBD, 0x54, \\\n                   0xFC, 0xBE, 0x97, 0x1C}\n#define Curve_B_2 {0xB1, 0xB9, 0x46, 0xC1, 0xEC, 0xDE, 0xB8, 0xFE, \\\n                   0x49, 0x30, 0x24, 0x72, 0xAB, 0xE9, 0xA7, 0x0F, \\\n                   0xE7, 0x80, 0x9C, 0xE5, 0x19, 0x05, 0x21, 0x64}\n#define Curve_B_3 {0x4B, 0x60, 0xD2, 0x27, 0x3E, 0x3C, 0xCE, 0x3B, \\\n                   0xF6, 0xB0, 0x53, 0xCC, 0xB0, 0x06, 0x1D, 0x65, \\\n                   0xBC, 0x86, 0x98, 0x76, 0x55, 0xBD, 0xEB, 0xB3, \\\n                   0xE7, 0x93, 0x3A, 0xAA, 0xD8, 0x35, 0xC6, 0x5A}\n#define Curve_B_4 {0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \\\n                   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \\\n                   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \\\n                   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}\n#define Curve_B_5 {0xB4, 0xFF, 0x55, 0x23, 0x43, 0x39, 0x0B, 0x27, \\\n                   0xBA, 0xD8, 0xBF, 0xD7, 0xB7, 0xB0, 0x44, 0x50, \\\n                   0x56, 0x32, 0x41, 0xF5, 0xAB, 0xB3, 0x04, 0x0C, \\\n                   0x85, 0x0A, 0x05, 0xB4}\n\n#define Curve_G_1 { \\\n    {0x82, 0xFC, 0xCB, 0x13, 0xB9, 0x8B, 0xC3, 0x68, \\\n        0x89, 0x69, 0x64, 0x46, 0x28, 0x73, 0xF5, 0x8E, \\\n        0x68, 0xB5, 0x96, 0x4A}, \\\n    {0x32, 0xFB, 0xC5, 0x7A, 0x37, 0x51, 0x23, 0x04, \\\n        0x12, 0xC9, 0xDC, 0x59, 0x7D, 0x94, 0x68, 0x31, \\\n        0x55, 0x28, 0xA6, 0x23}}\n\n#define Curve_G_2 { \\\n    {0x12, 0x10, 0xFF, 0x82, 0xFD, 0x0A, 0xFF, 0xF4, \\\n        0x00, 0x88, 0xA1, 0x43, 0xEB, 0x20, 0xBF, 0x7C, \\\n        0xF6, 0x90, 0x30, 0xB0, 0x0E, 0xA8, 0x8D, 0x18}, \\\n    {0x11, 0x48, 0x79, 0x1E, 0xA1, 0x77, 0xF9, 0x73, \\\n        0xD5, 0xCD, 0x24, 0x6B, 0xED, 0x11, 0x10, 0x63, \\\n        0x78, 0xDA, 0xC8, 0xFF, 0x95, 0x2B, 0x19, 0x07}}\n\n#define Curve_G_3 { \\\n    {0x96, 0xC2, 0x98, 0xD8, 0x45, 0x39, 0xA1, 0xF4, \\\n        0xA0, 0x33, 0xEB, 0x2D, 0x81, 0x7D, 0x03, 0x77, \\\n        0xF2, 0x40, 0xA4, 0x63, 0xE5, 0xE6, 0xBC, 0xF8, \\\n        0x47, 0x42, 0x2C, 0xE1, 0xF2, 0xD1, 0x17, 0x6B}, \\\n    {0xF5, 0x51, 0xBF, 0x37, 0x68, 0x40, 0xB6, 0xCB, \\\n        0xCE, 0x5E, 0x31, 0x6B, 0x57, 0x33, 0xCE, 0x2B, \\\n        0x16, 0x9E, 0x0F, 0x7C, 0x4A, 0xEB, 0xE7, 0x8E, \\\n        0x9B, 0x7F, 0x1A, 0xFE, 0xE2, 0x42, 0xE3, 0x4F}}\n\n#define Curve_G_4 { \\\n    {0x98, 0x17, 0xF8, 0x16, 0x5B, 0x81, 0xF2, 0x59, \\\n        0xD9, 0x28, 0xCE, 0x2D, 0xDB, 0xFC, 0x9B, 0x02, \\\n        0x07, 0x0B, 0x87, 0xCE, 0x95, 0x62, 0xA0, 0x55, \\\n        0xAC, 0xBB, 0xDC, 0xF9, 0x7E, 0x66, 0xBE, 0x79}, \\\n    {0xB8, 0xD4, 0x10, 0xFB, 0x8F, 0xD0, 0x47, 0x9C, \\\n        0x19, 0x54, 0x85, 0xA6, 0x48, 0xB4, 0x17, 0xFD, \\\n        0xA8, 0x08, 0x11, 0x0E, 0xFC, 0xFB, 0xA4, 0x5D, \\\n        0x65, 0xC4, 0xA3, 0x26, 0x77, 0xDA, 0x3A, 0x48}}\n\n#define Curve_G_5 { \\\n    {0x21, 0x1D, 0x5C, 0x11, 0xD6, 0x80, 0x32, 0x34, \\\n        0x22, 0x11, 0xC2, 0x56, 0xD3, 0xC1, 0x03, 0x4A, \\\n        0xB9, 0x90, 0x13, 0x32, 0x7F, 0xBF, 0xB4, 0x6B, \\\n        0xBD, 0x0C, 0x0E, 0xB7}, \\\n    {0x34, 0x7E, 0x00, 0x85, 0x99, 0x81, 0xD5, 0x44, \\\n        0x64, 0x47, 0x07, 0x5A, 0xA0, 0x75, 0x43, 0xCD, \\\n        0xE6, 0xDF, 0x22, 0x4C, 0xFB, 0x23, 0xF7, 0xB5, \\\n        0x88, 0x63, 0x37, 0xBD}}\n\n#define Curve_N_1 {0x57, 0x22, 0x75, 0xCA, 0xD3, 0xAE, 0x27, 0xF9, \\\n                   0xC8, 0xF4, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, \\\n                   0x00, 0x00, 0x00, 0x00, 0x01}\n#define Curve_N_2 {0x31, 0x28, 0xD2, 0xB4, 0xB1, 0xC9, 0x6B, 0x14, \\\n                   0x36, 0xF8, 0xDE, 0x99, 0xFF, 0xFF, 0xFF, 0xFF, \\\n                   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}\n#define Curve_N_3 {0x51, 0x25, 0x63, 0xFC, 0xC2, 0xCA, 0xB9, 0xF3, \\\n                   0x84, 0x9E, 0x17, 0xA7, 0xAD, 0xFA, 0xE6, 0xBC, \\\n                   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \\\n                   0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF}\n#define Curve_N_4 {0x41, 0x41, 0x36, 0xD0, 0x8C, 0x5E, 0xD2, 0xBF, \\\n                   0x3B, 0xA0, 0x48, 0xAF, 0xE6, 0xDC, 0xAE, 0xBA, \\\n                   0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \\\n                   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}\n#define Curve_N_5 {0x3D, 0x2A, 0x5C, 0x5C, 0x45, 0x29, 0xDD, 0x13, \\\n                   0x3E, 0xF0, 0xB8, 0xE0, 0xA2, 0x16, 0xFF, 0xFF, \\\n                   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \\\n                   0xFF, 0xFF, 0xFF, 0xFF}\n\n#elif (uECC_WORD_SIZE == 4)\n\ntypedef uint32_t uECC_word_t;\ntypedef uint64_t uECC_dword_t;\ntypedef unsigned wordcount_t;\ntypedef int swordcount_t;\ntypedef int bitcount_t;\ntypedef int cmpresult_t;\n\n#define HIGH_BIT_SET 0x80000000\n#define uECC_WORD_BITS 32\n#define uECC_WORD_BITS_SHIFT 5\n#define uECC_WORD_BITS_MASK 0x01F\n\n#define uECC_WORDS_1 5\n#define uECC_WORDS_2 6\n#define uECC_WORDS_3 8\n#define uECC_WORDS_4 8\n#define uECC_WORDS_5 7\n\n#define uECC_N_WORDS_1 6\n#define uECC_N_WORDS_2 6\n#define uECC_N_WORDS_3 8\n#define uECC_N_WORDS_4 8\n#define uECC_N_WORDS_5 7\n\n#define Curve_P_1 {0x7FFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF}\n#define Curve_P_2 {0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF}\n#define Curve_P_3 {0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, \\\n                   0x00000000, 0x00000000, 0x00000001, 0xFFFFFFFF}\n#define Curve_P_4 {0xFFFFFC2F, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, \\\n                   0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF}\n#define Curve_P_5 {0x00000001, 0x00000000, 0x00000000, 0xFFFFFFFF, \\\n                   0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF}\n\n#define Curve_B_1 {0xC565FA45, 0x81D4D4AD, 0x65ACF89F, 0x54BD7A8B, 0x1C97BEFC}\n#define Curve_B_2 {0xC146B9B1, 0xFEB8DEEC, 0x72243049, 0x0FA7E9AB, 0xE59C80E7, 0x64210519}\n#define Curve_B_3 {0x27D2604B, 0x3BCE3C3E, 0xCC53B0F6, 0x651D06B0, \\\n                   0x769886BC, 0xB3EBBD55, 0xAA3A93E7, 0x5AC635D8}\n#define Curve_B_4 {0x00000007, 0x00000000, 0x00000000, 0x00000000, \\\n                   0x00000000, 0x00000000, 0x00000000, 0x00000000}\n#define Curve_B_5 {0x2355FFB4, 0x270B3943, 0xD7BFD8BA, 0x5044B0B7, \\\n                   0xF5413256, 0x0C04B3AB, 0xB4050A85}\n\n#define Curve_G_1 { \\\n    {0x13CBFC82, 0x68C38BB9, 0x46646989, 0x8EF57328, 0x4A96B568}, \\\n    {0x7AC5FB32, 0x04235137, 0x59DCC912, 0x3168947D, 0x23A62855}}\n\n#define Curve_G_2 { \\\n    {0x82FF1012, 0xF4FF0AFD, 0x43A18800, 0x7CBF20EB, 0xB03090F6, 0x188DA80E}, \\\n    {0x1E794811, 0x73F977A1, 0x6B24CDD5, 0x631011ED, 0xFFC8DA78, 0x07192B95}}\n\n#define Curve_G_3 { \\\n    {0xD898C296, 0xF4A13945, 0x2DEB33A0, 0x77037D81,  \\\n     0x63A440F2, 0xF8BCE6E5, 0xE12C4247, 0x6B17D1F2}, \\\n    {0x37BF51F5, 0xCBB64068, 0x6B315ECE, 0x2BCE3357,  \\\n     0x7C0F9E16, 0x8EE7EB4A, 0xFE1A7F9B, 0x4FE342E2}}\n\n#define Curve_G_4 { \\\n    {0x16F81798, 0x59F2815B, 0x2DCE28D9, 0x029BFCDB,  \\\n     0xCE870B07, 0x55A06295, 0xF9DCBBAC, 0x79BE667E}, \\\n    {0xFB10D4B8, 0x9C47D08F, 0xA6855419, 0xFD17B448,  \\\n     0x0E1108A8, 0x5DA4FBFC, 0x26A3C465, 0x483ADA77}}\n\n#define Curve_G_5 { \\\n    {0x115C1D21, 0x343280D6, 0x56C21122, 0x4A03C1D3, \\\n     0x321390B9, 0x6BB4BF7F, 0xB70E0CBD}, \\\n    {0x85007E34, 0x44D58199, 0x5A074764, 0xCD4375A0, \\\n     0x4C22DFE6, 0xB5F723FB, 0xBD376388}}\n\n#define Curve_N_1 {0xCA752257, 0xF927AED3, 0x0001F4C8, 0x00000000, 0x00000000, 0x00000001}\n#define Curve_N_2 {0xB4D22831, 0x146BC9B1, 0x99DEF836, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF}\n#define Curve_N_3 {0xFC632551, 0xF3B9CAC2, 0xA7179E84, 0xBCE6FAAD, \\\n                   0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF}\n#define Curve_N_4 {0xD0364141, 0xBFD25E8C, 0xAF48A03B, 0xBAAEDCE6, \\\n                   0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF}\n#define Curve_N_5 {0x5C5C2A3D, 0x13DD2945, 0xE0B8F03E, 0xFFFF16A2, \\\n                   0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF}\n\n#elif (uECC_WORD_SIZE == 8)\n\ntypedef uint64_t uECC_word_t;\n#if SUPPORTS_INT128\ntypedef unsigned __int128 uECC_dword_t;\n#endif\ntypedef unsigned wordcount_t;\ntypedef int swordcount_t;\ntypedef int bitcount_t;\ntypedef int cmpresult_t;\n\n#define HIGH_BIT_SET 0x8000000000000000ull\n#define uECC_WORD_BITS 64\n#define uECC_WORD_BITS_SHIFT 6\n#define uECC_WORD_BITS_MASK 0x03F\n\n#define uECC_WORDS_1 3\n#define uECC_WORDS_2 3\n#define uECC_WORDS_3 4\n#define uECC_WORDS_4 4\n#define uECC_WORDS_5 4\n\n#define uECC_N_WORDS_1 3\n#define uECC_N_WORDS_2 3\n#define uECC_N_WORDS_3 4\n#define uECC_N_WORDS_4 4\n#define uECC_N_WORDS_5 4\n\n#define Curve_P_1 {0xFFFFFFFF7FFFFFFFull, 0xFFFFFFFFFFFFFFFFull, 0x00000000FFFFFFFFull}\n#define Curve_P_2 {0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFEull, 0xFFFFFFFFFFFFFFFFull}\n#define Curve_P_3 {0xFFFFFFFFFFFFFFFFull, 0x00000000FFFFFFFFull, \\\n                   0x0000000000000000ull, 0xFFFFFFFF00000001ull}\n#define Curve_P_4 {0xFFFFFFFEFFFFFC2Full, 0xFFFFFFFFFFFFFFFFull, \\\n                   0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull}\n#define Curve_P_5 {0x0000000000000001ull, 0xFFFFFFFF00000000ull, \\\n                   0xFFFFFFFFFFFFFFFFull, 0x00000000FFFFFFFFull}\n\n#define Curve_B_1 {0x81D4D4ADC565FA45ull, 0x54BD7A8B65ACF89Full, 0x000000001C97BEFCull}\n#define Curve_B_2 {0xFEB8DEECC146B9B1ull, 0x0FA7E9AB72243049ull, 0x64210519E59C80E7ull}\n#define Curve_B_3 {0x3BCE3C3E27D2604Bull, 0x651D06B0CC53B0F6ull, \\\n                   0xB3EBBD55769886BCull, 0x5AC635D8AA3A93E7ull}\n#define Curve_B_4 {0x0000000000000007ull, 0x0000000000000000ull, \\\n                   0x0000000000000000ull, 0x0000000000000000ull}\n#define Curve_B_5 {0x270B39432355FFB4ull, 0x5044B0B7D7BFD8BAull, \\\n                   0x0C04B3ABF5413256ull, 0x00000000B4050A85ull}\n\n#define Curve_G_1 { \\\n    {0x68C38BB913CBFC82ull, 0x8EF5732846646989ull, 0x000000004A96B568ull}, \\\n    {0x042351377AC5FB32ull, 0x3168947D59DCC912ull, 0x0000000023A62855ull}}\n\n#define Curve_G_2 { \\\n    {0xF4FF0AFD82FF1012ull, 0x7CBF20EB43A18800ull, 0x188DA80EB03090F6ull}, \\\n    {0x73F977A11E794811ull, 0x631011ED6B24CDD5ull, 0x07192B95FFC8DA78ull}}\n\n#define Curve_G_3 { \\\n    {0xF4A13945D898C296ull, 0x77037D812DEB33A0ull, 0xF8BCE6E563A440F2ull, 0x6B17D1F2E12C4247ull}, \\\n    {0xCBB6406837BF51F5ull, 0x2BCE33576B315ECEull, 0x8EE7EB4A7C0F9E16ull, 0x4FE342E2FE1A7F9Bull}}\n\n#define Curve_G_4 { \\\n    {0x59F2815B16F81798ull, 0x029BFCDB2DCE28D9ull, 0x55A06295CE870B07ull, 0x79BE667EF9DCBBACull}, \\\n    {0x9C47D08FFB10D4B8ull, 0xFD17B448A6855419ull, 0x5DA4FBFC0E1108A8ull, 0x483ADA7726A3C465ull}}\n\n#define Curve_G_5 { \\\n    {0x343280D6115C1D21ull, 0x4A03C1D356C21122ull, 0x6BB4BF7F321390B9ull, 0x00000000B70E0CBDull}, \\\n    {0x44D5819985007E34ull, 0xCD4375A05A074764ull, 0xB5F723FB4C22DFE6ull, 0x00000000BD376388ull}}\n\n#define Curve_N_1 {0xF927AED3CA752257ull, 0x000000000001F4C8ull, 0x0000000100000000ull}\n#define Curve_N_2 {0x146BC9B1B4D22831ull, 0xFFFFFFFF99DEF836ull, 0xFFFFFFFFFFFFFFFFull}\n#define Curve_N_3 {0xF3B9CAC2FC632551ull, 0xBCE6FAADA7179E84ull, \\\n                   0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFF00000000ull}\n#define Curve_N_4 {0xBFD25E8CD0364141ull, 0xBAAEDCE6AF48A03Bull, \\\n                   0xFFFFFFFFFFFFFFFEull, 0xFFFFFFFFFFFFFFFFull}\n#define Curve_N_5 {0x13DD29455C5C2A3Dull, 0xFFFF16A2E0B8F03Eull, \\\n                   0xFFFFFFFFFFFFFFFFull, 0x00000000FFFFFFFFull}\n\n#endif /* (uECC_WORD_SIZE == 8) */\n\n#define uECC_WORDS uECC_CONCAT(uECC_WORDS_, uECC_CURVE)\n#define uECC_N_WORDS uECC_CONCAT(uECC_N_WORDS_, uECC_CURVE)\n\ntypedef struct EccPoint {\n    uECC_word_t x[uECC_WORDS];\n    uECC_word_t y[uECC_WORDS];\n} EccPoint;\n\nstatic const uECC_word_t curve_p[uECC_WORDS] = uECC_CONCAT(Curve_P_, uECC_CURVE);\nstatic const uECC_word_t curve_b[uECC_WORDS] = uECC_CONCAT(Curve_B_, uECC_CURVE);\nstatic const EccPoint curve_G = uECC_CONCAT(Curve_G_, uECC_CURVE);\nstatic const uECC_word_t curve_n[uECC_N_WORDS] = uECC_CONCAT(Curve_N_, uECC_CURVE);\n\nstatic void vli_clear(uECC_word_t *vli);\nstatic uECC_word_t vli_isZero(const uECC_word_t *vli);\nstatic uECC_word_t vli_testBit(const uECC_word_t *vli, bitcount_t bit);\nstatic bitcount_t vli_numBits(const uECC_word_t *vli, wordcount_t max_words);\nstatic void vli_set(uECC_word_t *dest, const uECC_word_t *src);\nstatic cmpresult_t vli_cmp(const uECC_word_t *left, const uECC_word_t *right);\nstatic cmpresult_t vli_equal(const uECC_word_t *left, const uECC_word_t *right);\nstatic void vli_rshift1(uECC_word_t *vli);\nstatic uECC_word_t vli_add(uECC_word_t *result,\n                           const uECC_word_t *left,\n                           const uECC_word_t *right);\nstatic uECC_word_t vli_sub(uECC_word_t *result,\n                           const uECC_word_t *left,\n                           const uECC_word_t *right);\nstatic void vli_mult(uECC_word_t *result, const uECC_word_t *left, const uECC_word_t *right);\nstatic void vli_modAdd(uECC_word_t *result,\n                       const uECC_word_t *left,\n                       const uECC_word_t *right,\n                       const uECC_word_t *mod);\nstatic void vli_modSub(uECC_word_t *result,\n                       const uECC_word_t *left,\n                       const uECC_word_t *right,\n                       const uECC_word_t *mod);\nstatic void vli_mmod_fast(uECC_word_t *RESTRICT result, uECC_word_t *RESTRICT product);\nstatic void vli_modMult_fast(uECC_word_t *result,\n                             const uECC_word_t *left,\n                             const uECC_word_t *right);\nstatic void vli_modInv(uECC_word_t *result, const uECC_word_t *input, const uECC_word_t *mod);\n#if uECC_SQUARE_FUNC\nstatic void vli_square(uECC_word_t *result, const uECC_word_t *left);\nstatic void vli_modSquare_fast(uECC_word_t *result, const uECC_word_t *left);\n#endif\n\n#if (defined(_WIN32) || defined(_WIN64))\n/* Windows */\n\n#define WIN32_LEAN_AND_MEAN\n#include <windows.h>\n#include <wincrypt.h>\n\nstatic int default_RNG(uint8_t *dest, unsigned size) {\n    HCRYPTPROV prov;\n    if (!CryptAcquireContext(&prov, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) {\n        return 0;\n    }\n\n    CryptGenRandom(prov, size, (BYTE *)dest);\n    CryptReleaseContext(prov, 0);\n    return 1;\n}\n\n#elif defined(unix) || defined(__linux__) || defined(__unix__) || defined(__unix) || \\\n    (defined(__APPLE__) && defined(__MACH__)) || defined(uECC_POSIX)\n\n/* Some POSIX-like system with /dev/urandom or /dev/random. */\n#include <sys/types.h>\n#include <fcntl.h>\n#include <unistd.h>\n\n#ifndef O_CLOEXEC\n    #define O_CLOEXEC 0\n#endif\n\nstatic int default_RNG(uint8_t *dest, unsigned size) {\n    int fd = open(\"/dev/urandom\", O_RDONLY | O_CLOEXEC);\n    if (fd == -1) {\n        fd = open(\"/dev/random\", O_RDONLY | O_CLOEXEC);\n        if (fd == -1) {\n            return 0;\n        }\n    }\n\n    char *ptr = (char *)dest;\n    size_t left = size;\n    while (left > 0) {\n        ssize_t bytes_read = read(fd, ptr, left);\n        if (bytes_read <= 0) { // read failed\n            close(fd);\n            return 0;\n        }\n        left -= bytes_read;\n        ptr += bytes_read;\n    }\n\n    close(fd);\n    return 1;\n}\n\n#else /* Some other platform */\n\nstatic int default_RNG(uint8_t *dest, unsigned size) {\n    return 0;\n}\n\n#endif\n\nstatic uECC_RNG_Function g_rng_function = &default_RNG;\n\nvoid uECC_set_rng(uECC_RNG_Function rng_function) {\n    g_rng_function = rng_function;\n}\n\n#ifdef __GNUC__ /* Only support GCC inline asm for now */\n    #if (uECC_ASM && (uECC_PLATFORM == uECC_avr))\n        #include \"asm_avr.inc\"\n    #endif\n\n    #if (uECC_ASM && (uECC_PLATFORM == uECC_arm || uECC_PLATFORM == uECC_arm_thumb || \\\n                      uECC_PLATFORM == uECC_arm_thumb2))\n        #include \"asm_arm.inc\"\n    #endif\n#endif\n\n#if !asm_clear\nstatic void vli_clear(uECC_word_t *vli) {\n    wordcount_t i;\n    for (i = 0; i < uECC_WORDS; ++i) {\n        vli[i] = 0;\n    }\n}\n#endif\n\n/* Returns 1 if vli == 0, 0 otherwise. */\n#if !asm_isZero\nstatic uECC_word_t vli_isZero(const uECC_word_t *vli) {\n    wordcount_t i;\n    for (i = 0; i < uECC_WORDS; ++i) {\n        if (vli[i]) {\n            return 0;\n        }\n    }\n    return 1;\n}\n#endif\n\n/* Returns nonzero if bit 'bit' of vli is set. */\n#if !asm_testBit\nstatic uECC_word_t vli_testBit(const uECC_word_t *vli, bitcount_t bit) {\n    return (vli[bit >> uECC_WORD_BITS_SHIFT] & ((uECC_word_t)1 << (bit & uECC_WORD_BITS_MASK)));\n}\n#endif\n\n/* Counts the number of words in vli. */\n#if !asm_numBits\nstatic wordcount_t vli_numDigits(const uECC_word_t *vli, wordcount_t max_words) {\n    swordcount_t i;\n    /* Search from the end until we find a non-zero digit.\n       We do it in reverse because we expect that most digits will be nonzero. */\n    for (i = max_words - 1; i >= 0 && vli[i] == 0; --i) {\n    }\n\n    return (i + 1);\n}\n\n/* Counts the number of bits required to represent vli. */\nstatic bitcount_t vli_numBits(const uECC_word_t *vli, wordcount_t max_words) {\n    uECC_word_t i;\n    uECC_word_t digit;\n\n    wordcount_t num_digits = vli_numDigits(vli, max_words);\n    if (num_digits == 0) {\n        return 0;\n    }\n\n    digit = vli[num_digits - 1];\n    for (i = 0; digit; ++i) {\n        digit >>= 1;\n    }\n\n    return (((bitcount_t)(num_digits - 1) << uECC_WORD_BITS_SHIFT) + i);\n}\n#endif /* !asm_numBits */\n\n/* Sets dest = src. */\n#if !asm_set\nstatic void vli_set(uECC_word_t *dest, const uECC_word_t *src) {\n    wordcount_t i;\n    for (i = 0; i < uECC_WORDS; ++i) {\n        dest[i] = src[i];\n    }\n}\n#endif\n\n/* Returns sign of left - right. */\n#if !asm_cmp\nstatic cmpresult_t vli_cmp(const uECC_word_t *left, const uECC_word_t *right) {\n    swordcount_t i;\n    for (i = uECC_WORDS - 1; i >= 0; --i) {\n        if (left[i] > right[i]) {\n            return 1;\n        } else if (left[i] < right[i]) {\n            return -1;\n        }\n    }\n    return 0;\n}\n#endif\n\nstatic cmpresult_t vli_equal(const uECC_word_t *left, const uECC_word_t *right) {\n    uECC_word_t result = 0;\n    swordcount_t i;\n    for (i = uECC_WORDS - 1; i >= 0; --i) {\n        result |= (left[i] ^ right[i]);\n    }\n    return (result == 0);\n}\n\n/* Computes vli = vli >> 1. */\n#if !asm_rshift1\nstatic void vli_rshift1(uECC_word_t *vli) {\n    uECC_word_t *end = vli;\n    uECC_word_t carry = 0;\n\n    vli += uECC_WORDS;\n    while (vli-- > end) {\n        uECC_word_t temp = *vli;\n        *vli = (temp >> 1) | carry;\n        carry = temp << (uECC_WORD_BITS - 1);\n    }\n}\n#endif\n\n/* Computes result = left + right, returning carry. Can modify in place. */\n#if !asm_add\nstatic uECC_word_t vli_add(uECC_word_t *result, const uECC_word_t *left, const uECC_word_t *right) {\n    uECC_word_t carry = 0;\n    wordcount_t i;\n    for (i = 0; i < uECC_WORDS; ++i) {\n        uECC_word_t sum = left[i] + right[i] + carry;\n        if (sum != left[i]) {\n            carry = (sum < left[i]);\n        }\n        result[i] = sum;\n    }\n    return carry;\n}\n#endif\n\n/* Computes result = left - right, returning borrow. Can modify in place. */\n#if !asm_sub\nstatic uECC_word_t vli_sub(uECC_word_t *result, const uECC_word_t *left, const uECC_word_t *right) {\n    uECC_word_t borrow = 0;\n    wordcount_t i;\n    for (i = 0; i < uECC_WORDS; ++i) {\n        uECC_word_t diff = left[i] - right[i] - borrow;\n        if (diff != left[i]) {\n            borrow = (diff > left[i]);\n        }\n        result[i] = diff;\n    }\n    return borrow;\n}\n#endif\n\n#if (!asm_mult || (uECC_SQUARE_FUNC && !asm_square) || uECC_CURVE == uECC_secp256k1)\nstatic void muladd(uECC_word_t a,\n                   uECC_word_t b,\n                   uECC_word_t *r0,\n                   uECC_word_t *r1,\n                   uECC_word_t *r2) {\n#if uECC_WORD_SIZE == 8 && !SUPPORTS_INT128\n    uint64_t a0 = a & 0xffffffffull;\n    uint64_t a1 = a >> 32;\n    uint64_t b0 = b & 0xffffffffull;\n    uint64_t b1 = b >> 32;\n\n    uint64_t i0 = a0 * b0;\n    uint64_t i1 = a0 * b1;\n    uint64_t i2 = a1 * b0;\n    uint64_t i3 = a1 * b1;\n\n    uint64_t p0, p1;\n\n    i2 += (i0 >> 32);\n    i2 += i1;\n    if (i2 < i1) { // overflow\n        i3 += 0x100000000ull;\n    }\n\n    p0 = (i0 & 0xffffffffull) | (i2 << 32);\n    p1 = i3 + (i2 >> 32);\n\n    *r0 += p0;\n    *r1 += (p1 + (*r0 < p0));\n    *r2 += ((*r1 < p1) || (*r1 == p1 && *r0 < p0));\n#else\n    uECC_dword_t p = (uECC_dword_t)a * b;\n    uECC_dword_t r01 = ((uECC_dword_t)(*r1) << uECC_WORD_BITS) | *r0;\n    r01 += p;\n    *r2 += (r01 < p);\n    *r1 = r01 >> uECC_WORD_BITS;\n    *r0 = (uECC_word_t)r01;\n#endif\n}\n#define muladd_exists 1\n#endif\n\n#if !asm_mult\nstatic void vli_mult(uECC_word_t *result, const uECC_word_t *left, const uECC_word_t *right) {\n    uECC_word_t r0 = 0;\n    uECC_word_t r1 = 0;\n    uECC_word_t r2 = 0;\n    wordcount_t i, k;\n\n    /* Compute each digit of result in sequence, maintaining the carries. */\n    for (k = 0; k < uECC_WORDS; ++k) {\n        for (i = 0; i <= k; ++i) {\n            muladd(left[i], right[k - i], &r0, &r1, &r2);\n        }\n        result[k] = r0;\n        r0 = r1;\n        r1 = r2;\n        r2 = 0;\n    }\n    for (k = uECC_WORDS; k < uECC_WORDS * 2 - 1; ++k) {\n        for (i = (k + 1) - uECC_WORDS; i < uECC_WORDS; ++i) {\n            muladd(left[i], right[k - i], &r0, &r1, &r2);\n        }\n        result[k] = r0;\n        r0 = r1;\n        r1 = r2;\n        r2 = 0;\n    }\n    result[uECC_WORDS * 2 - 1] = r0;\n}\n#endif\n\n#if uECC_SQUARE_FUNC\n\n#if !asm_square\nstatic void mul2add(uECC_word_t a,\n                    uECC_word_t b,\n                    uECC_word_t *r0,\n                    uECC_word_t *r1,\n                    uECC_word_t *r2) {\n#if uECC_WORD_SIZE == 8 && !SUPPORTS_INT128\n    uint64_t a0 = a & 0xffffffffull;\n    uint64_t a1 = a >> 32;\n    uint64_t b0 = b & 0xffffffffull;\n    uint64_t b1 = b >> 32;\n\n    uint64_t i0 = a0 * b0;\n    uint64_t i1 = a0 * b1;\n    uint64_t i2 = a1 * b0;\n    uint64_t i3 = a1 * b1;\n\n    uint64_t p0, p1;\n\n    i2 += (i0 >> 32);\n    i2 += i1;\n    if (i2 < i1)\n    { // overflow\n        i3 += 0x100000000ull;\n    }\n\n    p0 = (i0 & 0xffffffffull) | (i2 << 32);\n    p1 = i3 + (i2 >> 32);\n\n    *r2 += (p1 >> 63);\n    p1 = (p1 << 1) | (p0 >> 63);\n    p0 <<= 1;\n\n    *r0 += p0;\n    *r1 += (p1 + (*r0 < p0));\n    *r2 += ((*r1 < p1) || (*r1 == p1 && *r0 < p0));\n#else\n    uECC_dword_t p = (uECC_dword_t)a * b;\n    uECC_dword_t r01 = ((uECC_dword_t)(*r1) << uECC_WORD_BITS) | *r0;\n    *r2 += (p >> (uECC_WORD_BITS * 2 - 1));\n    p *= 2;\n    r01 += p;\n    *r2 += (r01 < p);\n    *r1 = r01 >> uECC_WORD_BITS;\n    *r0 = (uECC_word_t)r01;\n#endif\n}\n\nstatic void vli_square(uECC_word_t *result, const uECC_word_t *left) {\n    uECC_word_t r0 = 0;\n    uECC_word_t r1 = 0;\n    uECC_word_t r2 = 0;\n\n    wordcount_t i, k;\n\n    for (k = 0; k < uECC_WORDS * 2 - 1; ++k) {\n        uECC_word_t min = (k < uECC_WORDS ? 0 : (k + 1) - uECC_WORDS);\n        for (i = min; i <= k && i <= k - i; ++i) {\n            if (i < k-i) {\n                mul2add(left[i], left[k - i], &r0, &r1, &r2);\n            } else {\n                muladd(left[i], left[k - i], &r0, &r1, &r2);\n            }\n        }\n        result[k] = r0;\n        r0 = r1;\n        r1 = r2;\n        r2 = 0;\n    }\n\n    result[uECC_WORDS * 2 - 1] = r0;\n}\n#endif\n\n#else /* uECC_SQUARE_FUNC */\n\n#define vli_square(result, left, size) vli_mult((result), (left), (left), (size))\n\n#endif /* uECC_SQUARE_FUNC */\n\n\n/* Computes result = (left + right) % mod.\n   Assumes that left < mod and right < mod, and that result does not overlap mod. */\n#if !asm_modAdd\nstatic void vli_modAdd(uECC_word_t *result,\n                       const uECC_word_t *left,\n                       const uECC_word_t *right,\n                       const uECC_word_t *mod) {\n    uECC_word_t carry = vli_add(result, left, right);\n    if (carry || vli_cmp(result, mod) >= 0) {\n        /* result > mod (result = mod + remainder), so subtract mod to get remainder. */\n        vli_sub(result, result, mod);\n    }\n}\n#endif\n\n/* Computes result = (left - right) % mod.\n   Assumes that left < mod and right < mod, and that result does not overlap mod. */\n#if !asm_modSub\nstatic void vli_modSub(uECC_word_t *result,\n                       const uECC_word_t *left,\n                       const uECC_word_t *right,\n                       const uECC_word_t *mod) {\n    uECC_word_t l_borrow = vli_sub(result, left, right);\n    if (l_borrow) {\n        /* In this case, result == -diff == (max int) - diff. Since -x % d == d - x,\n           we can get the correct result from result + mod (with overflow). */\n        vli_add(result, result, mod);\n    }\n}\n#endif\n\n#if !asm_modSub_fast\n    #define vli_modSub_fast(result, left, right) vli_modSub((result), (left), (right), curve_p)\n#endif\n\n#if !asm_mmod_fast\n\n#if (uECC_CURVE == uECC_secp160r1 || uECC_CURVE == uECC_secp256k1)\n/* omega_mult() is defined farther below for the different curves / word sizes */\nstatic void omega_mult(uECC_word_t * RESTRICT result, const uECC_word_t * RESTRICT right);\n\n/* Computes result = product % curve_p\n    see http://www.isys.uni-klu.ac.at/PDF/2001-0126-MT.pdf page 354\n\n    Note that this only works if log2(omega) < log2(p) / 2 */\nstatic void vli_mmod_fast(uECC_word_t *RESTRICT result, uECC_word_t *RESTRICT product) {\n    uECC_word_t tmp[2 * uECC_WORDS];\n    uECC_word_t carry;\n\n    vli_clear(tmp);\n    vli_clear(tmp + uECC_WORDS);\n\n    omega_mult(tmp, product + uECC_WORDS); /* (Rq, q) = q * c */\n\n    carry = vli_add(result, product, tmp); /* (C, r) = r + q       */\n    vli_clear(product);\n    omega_mult(product, tmp + uECC_WORDS); /* Rq*c */\n    carry += vli_add(result, result, product); /* (C1, r) = r + Rq*c */\n\n    while (carry > 0) {\n        --carry;\n        vli_sub(result, result, curve_p);\n    }\n    if (vli_cmp(result, curve_p) > 0) {\n        vli_sub(result, result, curve_p);\n    }\n}\n\n#endif\n\n#if uECC_CURVE == uECC_secp160r1\n\n#if uECC_WORD_SIZE == 1\nstatic void omega_mult(uint8_t * RESTRICT result, const uint8_t * RESTRICT right) {\n    uint8_t carry;\n    uint8_t i;\n\n    /* Multiply by (2^31 + 1). */\n    vli_set(result + 4, right); /* 2^32 */\n    vli_rshift1(result + 4); /* 2^31 */\n    result[3] = right[0] << 7; /* get last bit from shift */\n\n    carry = vli_add(result, result, right); /* 2^31 + 1 */\n    for (i = uECC_WORDS; carry; ++i) {\n        uint16_t sum = (uint16_t)result[i] + carry;\n        result[i] = (uint8_t)sum;\n        carry = sum >> 8;\n    }\n}\n#elif uECC_WORD_SIZE == 4\nstatic void omega_mult(uint32_t * RESTRICT result, const uint32_t * RESTRICT right) {\n    uint32_t carry;\n    unsigned i;\n\n    /* Multiply by (2^31 + 1). */\n    vli_set(result + 1, right); /* 2^32 */\n    vli_rshift1(result + 1); /* 2^31 */\n    result[0] = right[0] << 31; /* get last bit from shift */\n\n    carry = vli_add(result, result, right); /* 2^31 + 1 */\n    for (i = uECC_WORDS; carry; ++i) {\n        uint64_t sum = (uint64_t)result[i] + carry;\n        result[i] = (uint32_t)sum;\n        carry = sum >> 32;\n    }\n}\n#endif /* uECC_WORD_SIZE */\n\n#elif uECC_CURVE == uECC_secp192r1\n\n/* Computes result = product % curve_p.\n   See algorithm 5 and 6 from http://www.isys.uni-klu.ac.at/PDF/2001-0126-MT.pdf */\n#if uECC_WORD_SIZE == 1\nstatic void vli_mmod_fast(uint8_t *RESTRICT result, uint8_t *RESTRICT product) {\n    uint8_t tmp[uECC_WORDS];\n    uint8_t carry;\n\n    vli_set(result, product);\n\n    vli_set(tmp, &product[24]);\n    carry = vli_add(result, result, tmp);\n\n    tmp[0] = tmp[1] = tmp[2] = tmp[3] = tmp[4] = tmp[5] = tmp[6] = tmp[7] = 0;\n    tmp[8] = product[24]; tmp[9] = product[25]; tmp[10] = product[26]; tmp[11] = product[27];\n    tmp[12] = product[28]; tmp[13] = product[29]; tmp[14] = product[30]; tmp[15] = product[31];\n    tmp[16] = product[32]; tmp[17] = product[33]; tmp[18] = product[34]; tmp[19] = product[35];\n    tmp[20] = product[36]; tmp[21] = product[37]; tmp[22] = product[38]; tmp[23] = product[39];\n    carry += vli_add(result, result, tmp);\n\n    tmp[0] = tmp[8] = product[40];\n    tmp[1] = tmp[9] = product[41];\n    tmp[2] = tmp[10] = product[42];\n    tmp[3] = tmp[11] = product[43];\n    tmp[4] = tmp[12] = product[44];\n    tmp[5] = tmp[13] = product[45];\n    tmp[6] = tmp[14] = product[46];\n    tmp[7] = tmp[15] = product[47];\n    tmp[16] = tmp[17] = tmp[18] = tmp[19] = tmp[20] = tmp[21] = tmp[22] = tmp[23] = 0;\n    carry += vli_add(result, result, tmp);\n\n    while (carry || vli_cmp(curve_p, result) != 1) {\n        carry -= vli_sub(result, result, curve_p);\n    }\n}\n#elif uECC_WORD_SIZE == 4\nstatic void vli_mmod_fast(uint32_t *RESTRICT result, uint32_t *RESTRICT product) {\n    uint32_t tmp[uECC_WORDS];\n    int carry;\n\n    vli_set(result, product);\n\n    vli_set(tmp, &product[6]);\n    carry = vli_add(result, result, tmp);\n\n    tmp[0] = tmp[1] = 0;\n    tmp[2] = product[6];\n    tmp[3] = product[7];\n    tmp[4] = product[8];\n    tmp[5] = product[9];\n    carry += vli_add(result, result, tmp);\n\n    tmp[0] = tmp[2] = product[10];\n    tmp[1] = tmp[3] = product[11];\n    tmp[4] = tmp[5] = 0;\n    carry += vli_add(result, result, tmp);\n\n    while (carry || vli_cmp(curve_p, result) != 1) {\n        carry -= vli_sub(result, result, curve_p);\n    }\n}\n#else\nstatic void vli_mmod_fast(uint64_t *RESTRICT result, uint64_t *RESTRICT product) {\n    uint64_t tmp[uECC_WORDS];\n    int carry;\n\n    vli_set(result, product);\n\n    vli_set(tmp, &product[3]);\n    carry = vli_add(result, result, tmp);\n\n    tmp[0] = 0;\n    tmp[1] = product[3];\n    tmp[2] = product[4];\n    carry += vli_add(result, result, tmp);\n\n    tmp[0] = tmp[1] = product[5];\n    tmp[2] = 0;\n    carry += vli_add(result, result, tmp);\n\n    while (carry || vli_cmp(curve_p, result) != 1) {\n        carry -= vli_sub(result, result, curve_p);\n    }\n}\n#endif /* uECC_WORD_SIZE */\n\n#elif uECC_CURVE == uECC_secp256r1\n\n/* Computes result = product % curve_p\n   from http://www.nsa.gov/ia/_files/nist-routines.pdf */\n#if uECC_WORD_SIZE == 1\nstatic void vli_mmod_fast(uint8_t *RESTRICT result, uint8_t *RESTRICT product) {\n    uint8_t tmp[uECC_BYTES];\n    int8_t carry;\n\n    /* t */\n    vli_set(result, product);\n\n    /* s1 */\n    tmp[0] = tmp[1] = tmp[2] = tmp[3] = 0;\n    tmp[4] = tmp[5] = tmp[6] = tmp[7] = 0;\n    tmp[8] = tmp[9] = tmp[10] = tmp[11] = 0;\n    tmp[12] = product[44]; tmp[13] = product[45]; tmp[14] = product[46]; tmp[15] = product[47];\n    tmp[16] = product[48]; tmp[17] = product[49]; tmp[18] = product[50]; tmp[19] = product[51];\n    tmp[20] = product[52]; tmp[21] = product[53]; tmp[22] = product[54]; tmp[23] = product[55];\n    tmp[24] = product[56]; tmp[25] = product[57]; tmp[26] = product[58]; tmp[27] = product[59];\n    tmp[28] = product[60]; tmp[29] = product[61]; tmp[30] = product[62]; tmp[31] = product[63];\n    carry = vli_add(tmp, tmp, tmp);\n    carry += vli_add(result, result, tmp);\n\n    /* s2 */\n    tmp[12] = product[48]; tmp[13] = product[49]; tmp[14] = product[50]; tmp[15] = product[51];\n    tmp[16] = product[52]; tmp[17] = product[53]; tmp[18] = product[54]; tmp[19] = product[55];\n    tmp[20] = product[56]; tmp[21] = product[57]; tmp[22] = product[58]; tmp[23] = product[59];\n    tmp[24] = product[60]; tmp[25] = product[61]; tmp[26] = product[62]; tmp[27] = product[63];\n    tmp[28] = tmp[29] = tmp[30] = tmp[31] = 0;\n    carry += vli_add(tmp, tmp, tmp);\n    carry += vli_add(result, result, tmp);\n\n    /* s3 */\n    tmp[0] = product[32]; tmp[1] = product[33]; tmp[2] = product[34]; tmp[3] = product[35];\n    tmp[4] = product[36]; tmp[5] = product[37]; tmp[6] = product[38]; tmp[7] = product[39];\n    tmp[8] = product[40]; tmp[9] = product[41]; tmp[10] = product[42]; tmp[11] = product[43];\n    tmp[12] = tmp[13] = tmp[14] = tmp[15] = 0;\n    tmp[16] = tmp[17] = tmp[18] = tmp[19] = 0;\n    tmp[20] = tmp[21] = tmp[22] = tmp[23] = 0;\n    tmp[24] = product[56]; tmp[25] = product[57]; tmp[26] = product[58]; tmp[27] = product[59];\n    tmp[28] = product[60]; tmp[29] = product[61]; tmp[30] = product[62]; tmp[31] = product[63];\n    carry += vli_add(result, result, tmp);\n\n    /* s4 */\n    tmp[0] = product[36]; tmp[1] = product[37]; tmp[2] = product[38]; tmp[3] = product[39];\n    tmp[4] = product[40]; tmp[5] = product[41]; tmp[6] = product[42]; tmp[7] = product[43];\n    tmp[8] = product[44]; tmp[9] = product[45]; tmp[10] = product[46]; tmp[11] = product[47];\n    tmp[12] = product[52]; tmp[13] = product[53]; tmp[14] = product[54]; tmp[15] = product[55];\n    tmp[16] = product[56]; tmp[17] = product[57]; tmp[18] = product[58]; tmp[19] = product[59];\n    tmp[20] = product[60]; tmp[21] = product[61]; tmp[22] = product[62]; tmp[23] = product[63];\n    tmp[24] = product[52]; tmp[25] = product[53]; tmp[26] = product[54]; tmp[27] = product[55];\n    tmp[28] = product[32]; tmp[29] = product[33]; tmp[30] = product[34]; tmp[31] = product[35];\n    carry += vli_add(result, result, tmp);\n\n    /* d1 */\n    tmp[0] = product[44]; tmp[1] = product[45]; tmp[2] = product[46]; tmp[3] = product[47];\n    tmp[4] = product[48]; tmp[5] = product[49]; tmp[6] = product[50]; tmp[7] = product[51];\n    tmp[8] = product[52]; tmp[9] = product[53]; tmp[10] = product[54]; tmp[11] = product[55];\n    tmp[12] = tmp[13] = tmp[14] = tmp[15] = 0;\n    tmp[16] = tmp[17] = tmp[18] = tmp[19] = 0;\n    tmp[20] = tmp[21] = tmp[22] = tmp[23] = 0;\n    tmp[24] = product[32]; tmp[25] = product[33]; tmp[26] = product[34]; tmp[27] = product[35];\n    tmp[28] = product[40]; tmp[29] = product[41]; tmp[30] = product[42]; tmp[31] = product[43];\n    carry -= vli_sub(result, result, tmp);\n\n    /* d2 */\n    tmp[0] = product[48]; tmp[1] = product[49]; tmp[2] = product[50]; tmp[3] = product[51];\n    tmp[4] = product[52]; tmp[5] = product[53]; tmp[6] = product[54]; tmp[7] = product[55];\n    tmp[8] = product[56]; tmp[9] = product[57]; tmp[10] = product[58]; tmp[11] = product[59];\n    tmp[12] = product[60]; tmp[13] = product[61]; tmp[14] = product[62]; tmp[15] = product[63];\n    tmp[16] = tmp[17] = tmp[18] = tmp[19] = 0;\n    tmp[20] = tmp[21] = tmp[22] = tmp[23] = 0;\n    tmp[24] = product[36]; tmp[25] = product[37]; tmp[26] = product[38]; tmp[27] = product[39];\n    tmp[28] = product[44]; tmp[29] = product[45]; tmp[30] = product[46]; tmp[31] = product[47];\n    carry -= vli_sub(result, result, tmp);\n\n    /* d3 */\n    tmp[0] = product[52]; tmp[1] = product[53]; tmp[2] = product[54]; tmp[3] = product[55];\n    tmp[4] = product[56]; tmp[5] = product[57]; tmp[6] = product[58]; tmp[7] = product[59];\n    tmp[8] = product[60]; tmp[9] = product[61]; tmp[10] = product[62]; tmp[11] = product[63];\n    tmp[12] = product[32]; tmp[13] = product[33]; tmp[14] = product[34]; tmp[15] = product[35];\n    tmp[16] = product[36]; tmp[17] = product[37]; tmp[18] = product[38]; tmp[19] = product[39];\n    tmp[20] = product[40]; tmp[21] = product[41]; tmp[22] = product[42]; tmp[23] = product[43];\n    tmp[24] = tmp[25] = tmp[26] = tmp[27] = 0;\n    tmp[28] = product[48]; tmp[29] = product[49]; tmp[30] = product[50]; tmp[31] = product[51];\n    carry -= vli_sub(result, result, tmp);\n\n    /* d4 */\n    tmp[0] = product[56]; tmp[1] = product[57]; tmp[2] = product[58]; tmp[3] = product[59];\n    tmp[4] = product[60]; tmp[5] = product[61]; tmp[6] = product[62]; tmp[7] = product[63];\n    tmp[8] = tmp[9] = tmp[10] = tmp[11] = 0;\n    tmp[12] = product[36]; tmp[13] = product[37]; tmp[14] = product[38]; tmp[15] = product[39];\n    tmp[16] = product[40]; tmp[17] = product[41]; tmp[18] = product[42]; tmp[19] = product[43];\n    tmp[20] = product[44]; tmp[21] = product[45]; tmp[22] = product[46]; tmp[23] = product[47];\n    tmp[24] = tmp[25] = tmp[26] = tmp[27] = 0;\n    tmp[28] = product[52]; tmp[29] = product[53]; tmp[30] = product[54]; tmp[31] = product[55];\n    carry -= vli_sub(result, result, tmp);\n\n    if (carry < 0) {\n        do {\n            carry += vli_add(result, result, curve_p);\n        } while (carry < 0);\n    } else {\n        while (carry || vli_cmp(curve_p, result) != 1) {\n            carry -= vli_sub(result, result, curve_p);\n        }\n    }\n}\n#elif uECC_WORD_SIZE == 4\nstatic void vli_mmod_fast(uint32_t *RESTRICT result, uint32_t *RESTRICT product) {\n    uint32_t tmp[uECC_WORDS];\n    int carry;\n\n    /* t */\n    vli_set(result, product);\n\n    /* s1 */\n    tmp[0] = tmp[1] = tmp[2] = 0;\n    tmp[3] = product[11];\n    tmp[4] = product[12];\n    tmp[5] = product[13];\n    tmp[6] = product[14];\n    tmp[7] = product[15];\n    carry = vli_add(tmp, tmp, tmp);\n    carry += vli_add(result, result, tmp);\n\n    /* s2 */\n    tmp[3] = product[12];\n    tmp[4] = product[13];\n    tmp[5] = product[14];\n    tmp[6] = product[15];\n    tmp[7] = 0;\n    carry += vli_add(tmp, tmp, tmp);\n    carry += vli_add(result, result, tmp);\n\n    /* s3 */\n    tmp[0] = product[8];\n    tmp[1] = product[9];\n    tmp[2] = product[10];\n    tmp[3] = tmp[4] = tmp[5] = 0;\n    tmp[6] = product[14];\n    tmp[7] = product[15];\n    carry += vli_add(result, result, tmp);\n\n    /* s4 */\n    tmp[0] = product[9];\n    tmp[1] = product[10];\n    tmp[2] = product[11];\n    tmp[3] = product[13];\n    tmp[4] = product[14];\n    tmp[5] = product[15];\n    tmp[6] = product[13];\n    tmp[7] = product[8];\n    carry += vli_add(result, result, tmp);\n\n    /* d1 */\n    tmp[0] = product[11];\n    tmp[1] = product[12];\n    tmp[2] = product[13];\n    tmp[3] = tmp[4] = tmp[5] = 0;\n    tmp[6] = product[8];\n    tmp[7] = product[10];\n    carry -= vli_sub(result, result, tmp);\n\n    /* d2 */\n    tmp[0] = product[12];\n    tmp[1] = product[13];\n    tmp[2] = product[14];\n    tmp[3] = product[15];\n    tmp[4] = tmp[5] = 0;\n    tmp[6] = product[9];\n    tmp[7] = product[11];\n    carry -= vli_sub(result, result, tmp);\n\n    /* d3 */\n    tmp[0] = product[13];\n    tmp[1] = product[14];\n    tmp[2] = product[15];\n    tmp[3] = product[8];\n    tmp[4] = product[9];\n    tmp[5] = product[10];\n    tmp[6] = 0;\n    tmp[7] = product[12];\n    carry -= vli_sub(result, result, tmp);\n\n    /* d4 */\n    tmp[0] = product[14];\n    tmp[1] = product[15];\n    tmp[2] = 0;\n    tmp[3] = product[9];\n    tmp[4] = product[10];\n    tmp[5] = product[11];\n    tmp[6] = 0;\n    tmp[7] = product[13];\n    carry -= vli_sub(result, result, tmp);\n\n    if (carry < 0) {\n        do {\n            carry += vli_add(result, result, curve_p);\n        } while (carry < 0);\n    } else {\n        while (carry || vli_cmp(curve_p, result) != 1) {\n            carry -= vli_sub(result, result, curve_p);\n        }\n    }\n}\n#else\nstatic void vli_mmod_fast(uint64_t *RESTRICT result, uint64_t *RESTRICT product) {\n    uint64_t tmp[uECC_WORDS];\n    int carry;\n\n    /* t */\n    vli_set(result, product);\n\n    /* s1 */\n    tmp[0] = 0;\n    tmp[1] = product[5] & 0xffffffff00000000ull;\n    tmp[2] = product[6];\n    tmp[3] = product[7];\n    carry = vli_add(tmp, tmp, tmp);\n    carry += vli_add(result, result, tmp);\n\n    /* s2 */\n    tmp[1] = product[6] << 32;\n    tmp[2] = (product[6] >> 32) | (product[7] << 32);\n    tmp[3] = product[7] >> 32;\n    carry += vli_add(tmp, tmp, tmp);\n    carry += vli_add(result, result, tmp);\n\n    /* s3 */\n    tmp[0] = product[4];\n    tmp[1] = product[5] & 0xffffffff;\n    tmp[2] = 0;\n    tmp[3] = product[7];\n    carry += vli_add(result, result, tmp);\n\n    /* s4 */\n    tmp[0] = (product[4] >> 32) | (product[5] << 32);\n    tmp[1] = (product[5] >> 32) | (product[6] & 0xffffffff00000000ull);\n    tmp[2] = product[7];\n    tmp[3] = (product[6] >> 32) | (product[4] << 32);\n    carry += vli_add(result, result, tmp);\n\n    /* d1 */\n    tmp[0] = (product[5] >> 32) | (product[6] << 32);\n    tmp[1] = (product[6] >> 32);\n    tmp[2] = 0;\n    tmp[3] = (product[4] & 0xffffffff) | (product[5] << 32);\n    carry -= vli_sub(result, result, tmp);\n\n    /* d2 */\n    tmp[0] = product[6];\n    tmp[1] = product[7];\n    tmp[2] = 0;\n    tmp[3] = (product[4] >> 32) | (product[5] & 0xffffffff00000000ull);\n    carry -= vli_sub(result, result, tmp);\n\n    /* d3 */\n    tmp[0] = (product[6] >> 32) | (product[7] << 32);\n    tmp[1] = (product[7] >> 32) | (product[4] << 32);\n    tmp[2] = (product[4] >> 32) | (product[5] << 32);\n    tmp[3] = (product[6] << 32);\n    carry -= vli_sub(result, result, tmp);\n\n    /* d4 */\n    tmp[0] = product[7];\n    tmp[1] = product[4] & 0xffffffff00000000ull;\n    tmp[2] = product[5];\n    tmp[3] = product[6] & 0xffffffff00000000ull;\n    carry -= vli_sub(result, result, tmp);\n\n    if (carry < 0) {\n        do {\n            carry += vli_add(result, result, curve_p);\n        } while (carry < 0);\n    } else {\n        while (carry || vli_cmp(curve_p, result) != 1) {\n            carry -= vli_sub(result, result, curve_p);\n        }\n    }\n}\n#endif /* uECC_WORD_SIZE */\n\n#elif uECC_CURVE == uECC_secp256k1\n\n#if uECC_WORD_SIZE == 1\nstatic void omega_mult(uint8_t * RESTRICT result, const uint8_t * RESTRICT right) {\n    /* Multiply by (2^32 + 2^9 + 2^8 + 2^7 + 2^6 + 2^4 + 1). */\n    uECC_word_t r0 = 0;\n    uECC_word_t r1 = 0;\n    uECC_word_t r2 = 0;\n    wordcount_t k;\n\n    /* Multiply by (2^9 + 2^8 + 2^7 + 2^6 + 2^4 + 1). */\n    muladd(0xD1, right[0], &r0, &r1, &r2);\n    result[0] = r0;\n    r0 = r1;\n    r1 = r2;\n    /* r2 is still 0 */\n\n    for (k = 1; k < uECC_WORDS; ++k) {\n        muladd(0x03, right[k - 1], &r0, &r1, &r2);\n        muladd(0xD1, right[k], &r0, &r1, &r2);\n        result[k] = r0;\n        r0 = r1;\n        r1 = r2;\n        r2 = 0;\n    }\n    muladd(0x03, right[uECC_WORDS - 1], &r0, &r1, &r2);\n    result[uECC_WORDS] = r0;\n    result[uECC_WORDS + 1] = r1;\n\n    result[4 + uECC_WORDS] = vli_add(result + 4, result + 4, right); /* add the 2^32 multiple */\n}\n#elif uECC_WORD_SIZE == 4\nstatic void omega_mult(uint32_t * RESTRICT result, const uint32_t * RESTRICT right) {\n    /* Multiply by (2^9 + 2^8 + 2^7 + 2^6 + 2^4 + 1). */\n    uint32_t carry = 0;\n    wordcount_t k;\n\n    for (k = 0; k < uECC_WORDS; ++k) {\n        uint64_t p = (uint64_t)0x3D1 * right[k] + carry;\n        result[k] = (p & 0xffffffff);\n        carry = p >> 32;\n    }\n    result[uECC_WORDS] = carry;\n\n    result[1 + uECC_WORDS] = vli_add(result + 1, result + 1, right); /* add the 2^32 multiple */\n}\n#else\nstatic void omega_mult(uint64_t * RESTRICT result, const uint64_t * RESTRICT right) {\n    uECC_word_t r0 = 0;\n    uECC_word_t r1 = 0;\n    uECC_word_t r2 = 0;\n    wordcount_t k;\n\n    /* Multiply by (2^32 + 2^9 + 2^8 + 2^7 + 2^6 + 2^4 + 1). */\n    for (k = 0; k < uECC_WORDS; ++k) {\n        muladd(0x1000003D1ull, right[k], &r0, &r1, &r2);\n        result[k] = r0;\n        r0 = r1;\n        r1 = r2;\n        r2 = 0;\n    }\n    result[uECC_WORDS] = r0;\n}\n#endif /* uECC_WORD_SIZE */\n\n#elif uECC_CURVE == uECC_secp224r1\n\n/* Computes result = product % curve_p\n   from http://www.nsa.gov/ia/_files/nist-routines.pdf */\n#if uECC_WORD_SIZE == 1\n// TODO it may be faster to use the omega_mult method when fully asm optimized.\nvoid vli_mmod_fast(uint8_t *RESTRICT result, uint8_t *RESTRICT product) {\n    uint8_t tmp[uECC_WORDS];\n    int8_t carry;\n\n    /* t */\n    vli_set(result, product);\n\n    /* s1 */\n    tmp[0] = tmp[1] = tmp[2] = tmp[3] = 0;\n    tmp[4] = tmp[5] = tmp[6] = tmp[7] = 0;\n    tmp[8] = tmp[9] = tmp[10] = tmp[11] = 0;\n    tmp[12] = product[28]; tmp[13] = product[29]; tmp[14] = product[30]; tmp[15] = product[31];\n    tmp[16] = product[32]; tmp[17] = product[33]; tmp[18] = product[34]; tmp[19] = product[35];\n    tmp[20] = product[36]; tmp[21] = product[37]; tmp[22] = product[38]; tmp[23] = product[39];\n    tmp[24] = product[40]; tmp[25] = product[41]; tmp[26] = product[42]; tmp[27] = product[43];\n    carry = vli_add(result, result, tmp);\n\n    /* s2 */\n    tmp[12] = product[44]; tmp[13] = product[45]; tmp[14] = product[46]; tmp[15] = product[47];\n    tmp[16] = product[48]; tmp[17] = product[49]; tmp[18] = product[50]; tmp[19] = product[51];\n    tmp[20] = product[52]; tmp[21] = product[53]; tmp[22] = product[54]; tmp[23] = product[55];\n    tmp[24] = tmp[25] = tmp[26] = tmp[27] = 0;\n    carry += vli_add(result, result, tmp);\n\n    /* d1 */\n    tmp[0]  = product[28]; tmp[1]  = product[29]; tmp[2]  = product[30]; tmp[3]  = product[31];\n    tmp[4]  = product[32]; tmp[5]  = product[33]; tmp[6]  = product[34]; tmp[7]  = product[35];\n    tmp[8]  = product[36]; tmp[9]  = product[37]; tmp[10] = product[38]; tmp[11] = product[39];\n    tmp[12] = product[40]; tmp[13] = product[41]; tmp[14] = product[42]; tmp[15] = product[43];\n    tmp[16] = product[44]; tmp[17] = product[45]; tmp[18] = product[46]; tmp[19] = product[47];\n    tmp[20] = product[48]; tmp[21] = product[49]; tmp[22] = product[50]; tmp[23] = product[51];\n    tmp[24] = product[52]; tmp[25] = product[53]; tmp[26] = product[54]; tmp[27] = product[55];\n    carry -= vli_sub(result, result, tmp);\n\n    /* d2 */\n    tmp[0]  = product[44]; tmp[1]  = product[45]; tmp[2]  = product[46]; tmp[3]  = product[47];\n    tmp[4]  = product[48]; tmp[5]  = product[49]; tmp[6]  = product[50]; tmp[7]  = product[51];\n    tmp[8]  = product[52]; tmp[9]  = product[53]; tmp[10] = product[54]; tmp[11] = product[55];\n    tmp[12] = tmp[13] = tmp[14] = tmp[15] = 0;\n    tmp[16] = tmp[17] = tmp[18] = tmp[19] = 0;\n    tmp[20] = tmp[21] = tmp[22] = tmp[23] = 0;\n    tmp[24] = tmp[25] = tmp[26] = tmp[27] = 0;\n    carry -= vli_sub(result, result, tmp);\n\n    if (carry < 0) {\n        do {\n            carry += vli_add(result, result, curve_p);\n        } while (carry < 0);\n    } else {\n        while (carry || vli_cmp(curve_p, result) != 1) {\n            carry -= vli_sub(result, result, curve_p);\n        }\n    }\n}\n#elif uECC_WORD_SIZE == 4\nvoid vli_mmod_fast(uint32_t *RESTRICT result, uint32_t *RESTRICT product)\n{\n    uint32_t tmp[uECC_WORDS];\n    int carry;\n\n    /* t */\n    vli_set(result, product);\n\n    /* s1 */\n    tmp[0] = tmp[1] = tmp[2] = 0;\n    tmp[3] = product[7];\n    tmp[4] = product[8];\n    tmp[5] = product[9];\n    tmp[6] = product[10];\n    carry = vli_add(result, result, tmp);\n\n    /* s2 */\n    tmp[3] = product[11];\n    tmp[4] = product[12];\n    tmp[5] = product[13];\n    tmp[6] = 0;\n    carry += vli_add(result, result, tmp);\n\n    /* d1 */\n    tmp[0] = product[7];\n    tmp[1] = product[8];\n    tmp[2] = product[9];\n    tmp[3] = product[10];\n    tmp[4] = product[11];\n    tmp[5] = product[12];\n    tmp[6] = product[13];\n    carry -= vli_sub(result, result, tmp);\n\n    /* d2 */\n    tmp[0] = product[11];\n    tmp[1] = product[12];\n    tmp[2] = product[13];\n    tmp[3] = tmp[4] = tmp[5] = tmp[6] = 0;\n    carry -= vli_sub(result, result, tmp);\n\n    if (carry < 0) {\n        do {\n            carry += vli_add(result, result, curve_p);\n        } while (carry < 0);\n    } else {\n        while (carry || vli_cmp(curve_p, result) != 1) {\n            carry -= vli_sub(result, result, curve_p);\n        }\n    }\n}\n#endif /* uECC_WORD_SIZE */\n\n#endif /* uECC_CURVE */\n#endif /* !asm_mmod_fast */\n\n/* Computes result = (left * right) % curve_p. */\nstatic void vli_modMult_fast(uECC_word_t *result,\n                             const uECC_word_t *left,\n                             const uECC_word_t *right) {\n    uECC_word_t product[2 * uECC_WORDS];\n    vli_mult(product, left, right);\n    vli_mmod_fast(result, product);\n}\n\n#if uECC_SQUARE_FUNC\n\n/* Computes result = left^2 % curve_p. */\nstatic void vli_modSquare_fast(uECC_word_t *result, const uECC_word_t *left) {\n    uECC_word_t product[2 * uECC_WORDS];\n    vli_square(product, left);\n    vli_mmod_fast(result, product);\n}\n\n#else /* uECC_SQUARE_FUNC */\n\n#define vli_modSquare_fast(result, left) vli_modMult_fast((result), (left), (left))\n\n#endif /* uECC_SQUARE_FUNC */\n\n\n#define EVEN(vli) (!(vli[0] & 1))\n/* Computes result = (1 / input) % mod. All VLIs are the same size.\n   See \"From Euclid's GCD to Montgomery Multiplication to the Great Divide\"\n   https://labs.oracle.com/techrep/2001/smli_tr-2001-95.pdf */\n#if !asm_modInv\nstatic void vli_modInv(uECC_word_t *result, const uECC_word_t *input, const uECC_word_t *mod) {\n    uECC_word_t a[uECC_WORDS], b[uECC_WORDS], u[uECC_WORDS], v[uECC_WORDS];\n    uECC_word_t carry;\n    cmpresult_t cmpResult;\n\n    if (vli_isZero(input)) {\n        vli_clear(result);\n        return;\n    }\n\n    vli_set(a, input);\n    vli_set(b, mod);\n    vli_clear(u);\n    u[0] = 1;\n    vli_clear(v);\n    while ((cmpResult = vli_cmp(a, b)) != 0) {\n        carry = 0;\n        if (EVEN(a)) {\n            vli_rshift1(a);\n            if (!EVEN(u)) {\n                carry = vli_add(u, u, mod);\n            }\n            vli_rshift1(u);\n            if (carry) {\n                u[uECC_WORDS - 1] |= HIGH_BIT_SET;\n            }\n        } else if (EVEN(b)) {\n            vli_rshift1(b);\n            if (!EVEN(v)) {\n                carry = vli_add(v, v, mod);\n            }\n            vli_rshift1(v);\n            if (carry) {\n                v[uECC_WORDS - 1] |= HIGH_BIT_SET;\n            }\n        } else if (cmpResult > 0) {\n            vli_sub(a, a, b);\n            vli_rshift1(a);\n            if (vli_cmp(u, v) < 0) {\n                vli_add(u, u, mod);\n            }\n            vli_sub(u, u, v);\n            if (!EVEN(u)) {\n                carry = vli_add(u, u, mod);\n            }\n            vli_rshift1(u);\n            if (carry) {\n                u[uECC_WORDS - 1] |= HIGH_BIT_SET;\n            }\n        } else {\n            vli_sub(b, b, a);\n            vli_rshift1(b);\n            if (vli_cmp(v, u) < 0) {\n                vli_add(v, v, mod);\n            }\n            vli_sub(v, v, u);\n            if (!EVEN(v)) {\n                carry = vli_add(v, v, mod);\n            }\n            vli_rshift1(v);\n            if (carry) {\n                v[uECC_WORDS - 1] |= HIGH_BIT_SET;\n            }\n        }\n    }\n    vli_set(result, u);\n}\n#endif /* !asm_modInv */\n\n/* ------ Point operations ------ */\n\n/* Returns 1 if 'point' is the point at infinity, 0 otherwise. */\nstatic cmpresult_t EccPoint_isZero(const EccPoint *point) {\n    return (vli_isZero(point->x) && vli_isZero(point->y));\n}\n\n/* Point multiplication algorithm using Montgomery's ladder with co-Z coordinates.\nFrom http://eprint.iacr.org/2011/338.pdf\n*/\n\n/* Double in place */\n#if (uECC_CURVE == uECC_secp256k1)\nstatic void EccPoint_double_jacobian(uECC_word_t * RESTRICT X1,\n                                     uECC_word_t * RESTRICT Y1,\n                                     uECC_word_t * RESTRICT Z1) {\n    /* t1 = X, t2 = Y, t3 = Z */\n    uECC_word_t t4[uECC_WORDS];\n    uECC_word_t t5[uECC_WORDS];\n\n    if (vli_isZero(Z1)) {\n        return;\n    }\n\n    vli_modSquare_fast(t5, Y1);   /* t5 = y1^2 */\n    vli_modMult_fast(t4, X1, t5); /* t4 = x1*y1^2 = A */\n    vli_modSquare_fast(X1, X1);   /* t1 = x1^2 */\n    vli_modSquare_fast(t5, t5);   /* t5 = y1^4 */\n    vli_modMult_fast(Z1, Y1, Z1); /* t3 = y1*z1 = z3 */\n\n    vli_modAdd(Y1, X1, X1, curve_p); /* t2 = 2*x1^2 */\n    vli_modAdd(Y1, Y1, X1, curve_p); /* t2 = 3*x1^2 */\n    if (vli_testBit(Y1, 0)) {\n        uECC_word_t carry = vli_add(Y1, Y1, curve_p);\n        vli_rshift1(Y1);\n        Y1[uECC_WORDS - 1] |= carry << (uECC_WORD_BITS - 1);\n    } else {\n        vli_rshift1(Y1);\n    }\n    /* t2 = 3/2*(x1^2) = B */\n\n    vli_modSquare_fast(X1, Y1);      /* t1 = B^2 */\n    vli_modSub(X1, X1, t4, curve_p); /* t1 = B^2 - A */\n    vli_modSub(X1, X1, t4, curve_p); /* t1 = B^2 - 2A = x3 */\n\n    vli_modSub(t4, t4, X1, curve_p); /* t4 = A - x3 */\n    vli_modMult_fast(Y1, Y1, t4);    /* t2 = B * (A - x3) */\n    vli_modSub(Y1, Y1, t5, curve_p); /* t2 = B * (A - x3) - y1^4 = y3 */\n}\n#else\nstatic void EccPoint_double_jacobian(uECC_word_t * RESTRICT X1,\n                                     uECC_word_t * RESTRICT Y1,\n                                     uECC_word_t * RESTRICT Z1) {\n    /* t1 = X, t2 = Y, t3 = Z */\n    uECC_word_t t4[uECC_WORDS];\n    uECC_word_t t5[uECC_WORDS];\n\n    if (vli_isZero(Z1)) {\n        return;\n    }\n\n    vli_modSquare_fast(t4, Y1);   /* t4 = y1^2 */\n    vli_modMult_fast(t5, X1, t4); /* t5 = x1*y1^2 = A */\n    vli_modSquare_fast(t4, t4);   /* t4 = y1^4 */\n    vli_modMult_fast(Y1, Y1, Z1); /* t2 = y1*z1 = z3 */\n    vli_modSquare_fast(Z1, Z1);   /* t3 = z1^2 */\n\n    vli_modAdd(X1, X1, Z1, curve_p); /* t1 = x1 + z1^2 */\n    vli_modAdd(Z1, Z1, Z1, curve_p); /* t3 = 2*z1^2 */\n    vli_modSub_fast(Z1, X1, Z1);     /* t3 = x1 - z1^2 */\n    vli_modMult_fast(X1, X1, Z1);    /* t1 = x1^2 - z1^4 */\n\n    vli_modAdd(Z1, X1, X1, curve_p); /* t3 = 2*(x1^2 - z1^4) */\n    vli_modAdd(X1, X1, Z1, curve_p); /* t1 = 3*(x1^2 - z1^4) */\n    if (vli_testBit(X1, 0)) {\n        uECC_word_t l_carry = vli_add(X1, X1, curve_p);\n        vli_rshift1(X1);\n        X1[uECC_WORDS - 1] |= l_carry << (uECC_WORD_BITS - 1);\n    } else {\n        vli_rshift1(X1);\n    }\n    /* t1 = 3/2*(x1^2 - z1^4) = B */\n\n    vli_modSquare_fast(Z1, X1);   /* t3 = B^2 */\n    vli_modSub_fast(Z1, Z1, t5);  /* t3 = B^2 - A */\n    vli_modSub_fast(Z1, Z1, t5);  /* t3 = B^2 - 2A = x3 */\n    vli_modSub_fast(t5, t5, Z1);  /* t5 = A - x3 */\n    vli_modMult_fast(X1, X1, t5); /* t1 = B * (A - x3) */\n    vli_modSub_fast(t4, X1, t4);  /* t4 = B * (A - x3) - y1^4 = y3 */\n\n    vli_set(X1, Z1);\n    vli_set(Z1, Y1);\n    vli_set(Y1, t4);\n}\n#endif\n\n/* Modify (x1, y1) => (x1 * z^2, y1 * z^3) */\nstatic void apply_z(uECC_word_t * RESTRICT X1,\n                    uECC_word_t * RESTRICT Y1,\n                    const uECC_word_t * RESTRICT Z) {\n    uECC_word_t t1[uECC_WORDS];\n\n    vli_modSquare_fast(t1, Z);    /* z^2 */\n    vli_modMult_fast(X1, X1, t1); /* x1 * z^2 */\n    vli_modMult_fast(t1, t1, Z);  /* z^3 */\n    vli_modMult_fast(Y1, Y1, t1); /* y1 * z^3 */\n}\n\n/* P = (x1, y1) => 2P, (x2, y2) => P' */\nstatic void XYcZ_initial_double(uECC_word_t * RESTRICT X1,\n                                uECC_word_t * RESTRICT Y1,\n                                uECC_word_t * RESTRICT X2,\n                                uECC_word_t * RESTRICT Y2,\n                                const uECC_word_t * RESTRICT initial_Z) {\n    uECC_word_t z[uECC_WORDS];\n    if (initial_Z) {\n        vli_set(z, initial_Z);\n    } else {\n        vli_clear(z);\n        z[0] = 1;\n    }\n\n    vli_set(X2, X1);\n    vli_set(Y2, Y1);\n\n    apply_z(X1, Y1, z);\n    EccPoint_double_jacobian(X1, Y1, z);\n    apply_z(X2, Y2, z);\n}\n\n/* Input P = (x1, y1, Z), Q = (x2, y2, Z)\n   Output P' = (x1', y1', Z3), P + Q = (x3, y3, Z3)\n   or P => P', Q => P + Q\n*/\nstatic void XYcZ_add(uECC_word_t * RESTRICT X1,\n                     uECC_word_t * RESTRICT Y1,\n                     uECC_word_t * RESTRICT X2,\n                     uECC_word_t * RESTRICT Y2) {\n    /* t1 = X1, t2 = Y1, t3 = X2, t4 = Y2 */\n    uECC_word_t t5[uECC_WORDS];\n\n    vli_modSub_fast(t5, X2, X1);  /* t5 = x2 - x1 */\n    vli_modSquare_fast(t5, t5);   /* t5 = (x2 - x1)^2 = A */\n    vli_modMult_fast(X1, X1, t5); /* t1 = x1*A = B */\n    vli_modMult_fast(X2, X2, t5); /* t3 = x2*A = C */\n    vli_modSub_fast(Y2, Y2, Y1);  /* t4 = y2 - y1 */\n    vli_modSquare_fast(t5, Y2);   /* t5 = (y2 - y1)^2 = D */\n\n    vli_modSub_fast(t5, t5, X1);  /* t5 = D - B */\n    vli_modSub_fast(t5, t5, X2);  /* t5 = D - B - C = x3 */\n    vli_modSub_fast(X2, X2, X1);  /* t3 = C - B */\n    vli_modMult_fast(Y1, Y1, X2); /* t2 = y1*(C - B) */\n    vli_modSub_fast(X2, X1, t5);  /* t3 = B - x3 */\n    vli_modMult_fast(Y2, Y2, X2); /* t4 = (y2 - y1)*(B - x3) */\n    vli_modSub_fast(Y2, Y2, Y1);  /* t4 = y3 */\n\n    vli_set(X2, t5);\n}\n\n/* Input P = (x1, y1, Z), Q = (x2, y2, Z)\n   Output P + Q = (x3, y3, Z3), P - Q = (x3', y3', Z3)\n   or P => P - Q, Q => P + Q\n*/\nstatic void XYcZ_addC(uECC_word_t * RESTRICT X1,\n                      uECC_word_t * RESTRICT Y1,\n                      uECC_word_t * RESTRICT X2,\n                      uECC_word_t * RESTRICT Y2) {\n    /* t1 = X1, t2 = Y1, t3 = X2, t4 = Y2 */\n    uECC_word_t t5[uECC_WORDS];\n    uECC_word_t t6[uECC_WORDS];\n    uECC_word_t t7[uECC_WORDS];\n\n    vli_modSub_fast(t5, X2, X1);     /* t5 = x2 - x1 */\n    vli_modSquare_fast(t5, t5);      /* t5 = (x2 - x1)^2 = A */\n    vli_modMult_fast(X1, X1, t5);    /* t1 = x1*A = B */\n    vli_modMult_fast(X2, X2, t5);    /* t3 = x2*A = C */\n    vli_modAdd(t5, Y2, Y1, curve_p); /* t5 = y2 + y1 */\n    vli_modSub_fast(Y2, Y2, Y1);     /* t4 = y2 - y1 */\n\n    vli_modSub_fast(t6, X2, X1);     /* t6 = C - B */\n    vli_modMult_fast(Y1, Y1, t6);    /* t2 = y1 * (C - B) = E */\n    vli_modAdd(t6, X1, X2, curve_p); /* t6 = B + C */\n    vli_modSquare_fast(X2, Y2);      /* t3 = (y2 - y1)^2 = D */\n    vli_modSub_fast(X2, X2, t6);     /* t3 = D - (B + C) = x3 */\n\n    vli_modSub_fast(t7, X1, X2);  /* t7 = B - x3 */\n    vli_modMult_fast(Y2, Y2, t7); /* t4 = (y2 - y1)*(B - x3) */\n    vli_modSub_fast(Y2, Y2, Y1);  /* t4 = (y2 - y1)*(B - x3) - E = y3 */\n\n    vli_modSquare_fast(t7, t5);   /* t7 = (y2 + y1)^2 = F */\n    vli_modSub_fast(t7, t7, t6);  /* t7 = F - (B + C) = x3' */\n    vli_modSub_fast(t6, t7, X1);  /* t6 = x3' - B */\n    vli_modMult_fast(t6, t6, t5); /* t6 = (y2 + y1)*(x3' - B) */\n    vli_modSub_fast(Y1, t6, Y1);  /* t2 = (y2 + y1)*(x3' - B) - E = y3' */\n\n    vli_set(X1, t7);\n}\n\nstatic void EccPoint_mult(EccPoint * RESTRICT result,\n                          const EccPoint * RESTRICT point,\n                          const uECC_word_t * RESTRICT scalar,\n                          const uECC_word_t * RESTRICT initialZ,\n                          bitcount_t numBits) {\n    /* R0 and R1 */\n    uECC_word_t Rx[2][uECC_WORDS];\n    uECC_word_t Ry[2][uECC_WORDS];\n    uECC_word_t z[uECC_WORDS];\n    bitcount_t i;\n    uECC_word_t nb;\n\n    vli_set(Rx[1], point->x);\n    vli_set(Ry[1], point->y);\n\n    XYcZ_initial_double(Rx[1], Ry[1], Rx[0], Ry[0], initialZ);\n\n    for (i = numBits - 2; i > 0; --i) {\n        nb = !vli_testBit(scalar, i);\n        XYcZ_addC(Rx[1 - nb], Ry[1 - nb], Rx[nb], Ry[nb]);\n        XYcZ_add(Rx[nb], Ry[nb], Rx[1 - nb], Ry[1 - nb]);\n    }\n\n    nb = !vli_testBit(scalar, 0);\n    XYcZ_addC(Rx[1 - nb], Ry[1 - nb], Rx[nb], Ry[nb]);\n\n    /* Find final 1/Z value. */\n    vli_modSub_fast(z, Rx[1], Rx[0]);   /* X1 - X0 */\n    vli_modMult_fast(z, z, Ry[1 - nb]); /* Yb * (X1 - X0) */\n    vli_modMult_fast(z, z, point->x); /* xP * Yb * (X1 - X0) */\n    vli_modInv(z, z, curve_p);          /* 1 / (xP * Yb * (X1 - X0)) */\n    vli_modMult_fast(z, z, point->y); /* yP / (xP * Yb * (X1 - X0)) */\n    vli_modMult_fast(z, z, Rx[1 - nb]); /* Xb * yP / (xP * Yb * (X1 - X0)) */\n    /* End 1/Z calculation */\n\n    XYcZ_add(Rx[nb], Ry[nb], Rx[1 - nb], Ry[1 - nb]);\n    apply_z(Rx[0], Ry[0], z);\n\n    vli_set(result->x, Rx[0]);\n    vli_set(result->y, Ry[0]);\n}\n\nstatic int EccPoint_compute_public_key(EccPoint *result, uECC_word_t *private) {\n    uECC_word_t tmp1[uECC_WORDS];\n    uECC_word_t tmp2[uECC_WORDS];\n    uECC_word_t *p2[2] = {tmp1, tmp2};\n    uECC_word_t carry;\n\n    /* Make sure the private key is in the range [1, n-1]. */\n    if (vli_isZero(private)) {\n        return 0;\n    }\n\n#if (uECC_CURVE == uECC_secp160r1)\n    // Don't regularize the bitcount for secp160r1, since it would have a larger performance\n    // impact (about 2% slower on average) and requires the vli_xxx_n functions, leading to\n    // a significant increase in code size.\n\n    EccPoint_mult(result, &curve_G, private, 0, vli_numBits(private, uECC_WORDS));\n#else\n    if (vli_cmp(curve_n, private) != 1) {\n        return 0;\n    }\n\n    // Regularize the bitcount for the private key so that attackers cannot use a side channel\n    // attack to learn the number of leading zeros.\n    carry = vli_add(tmp1, private, curve_n);\n    vli_add(tmp2, tmp1, curve_n);\n    EccPoint_mult(result, &curve_G, p2[!carry], 0, (uECC_BYTES * 8) + 1);\n#endif\n\n    if (EccPoint_isZero(result)) {\n        return 0;\n    }\n    return 1;\n}\n\n#if uECC_CURVE == uECC_secp224r1\n\n/* Routine 3.2.4 RS;  from http://www.nsa.gov/ia/_files/nist-routines.pdf */\nstatic void mod_sqrt_secp224r1_rs(uECC_word_t *d1,\n                                  uECC_word_t *e1,\n                                  uECC_word_t *f1,\n                                  const uECC_word_t *d0,\n                                  const uECC_word_t *e0,\n                                  const uECC_word_t *f0) {\n    uECC_word_t t[uECC_WORDS];\n\n    vli_modSquare_fast(t, d0);                 /* t <-- d0 ^ 2 */\n    vli_modMult_fast(e1, d0, e0);              /* e1 <-- d0 * e0 */\n    vli_modAdd(d1, t, f0, curve_p);            /* d1 <-- t  + f0 */\n    vli_modAdd(e1, e1, e1, curve_p);           /* e1 <-- e1 + e1 */\n    vli_modMult_fast(f1, t, f0);               /* f1 <-- t  * f0 */\n    vli_modAdd(f1, f1, f1, curve_p);           /* f1 <-- f1 + f1 */\n    vli_modAdd(f1, f1, f1, curve_p);           /* f1 <-- f1 + f1 */\n}\n\n/* Routine 3.2.5 RSS;  from http://www.nsa.gov/ia/_files/nist-routines.pdf */\nstatic void mod_sqrt_secp224r1_rss(uECC_word_t *d1,\n                                   uECC_word_t *e1,\n                                   uECC_word_t *f1,\n                                   const uECC_word_t *d0,\n                                   const uECC_word_t *e0,\n                                   const uECC_word_t *f0,\n                                   const bitcount_t j) {\n    bitcount_t i;\n\n    vli_set(d1, d0);                           /* d1 <-- d0 */\n    vli_set(e1, e0);                           /* e1 <-- e0 */\n    vli_set(f1, f0);                           /* f1 <-- f0 */\n    for (i = 1; i <= j; i++) {\n        mod_sqrt_secp224r1_rs(d1, e1, f1, d1, e1, f1); /* RS (d1,e1,f1,d1,e1,f1) */\n    }\n}\n\n/* Routine 3.2.6 RM;  from http://www.nsa.gov/ia/_files/nist-routines.pdf */\nstatic void mod_sqrt_secp224r1_rm(uECC_word_t *d2,\n                                  uECC_word_t *e2,\n                                  uECC_word_t *f2,\n                                  const uECC_word_t *c,\n                                  const uECC_word_t *d0,\n                                  const uECC_word_t *e0,\n                                  const uECC_word_t *d1,\n                                  const uECC_word_t *e1) {\n    uECC_word_t t1[uECC_WORDS];\n    uECC_word_t t2[uECC_WORDS];\n\n    vli_modMult_fast(t1, e0, e1);              /* t1 <-- e0 * e1 */\n    vli_modMult_fast(t1, t1, c);               /* t1 <-- t1 * c */\n    vli_modSub_fast(t1, curve_p, t1);          /* t1 <-- p  - t1 */\n    vli_modMult_fast(t2, d0, d1);              /* t2 <-- d0 * d1 */\n    vli_modAdd(t2, t2, t1, curve_p);           /* t2 <-- t2 + t1 */\n    vli_modMult_fast(t1, d0, e1);              /* t1 <-- d0 * e1 */\n    vli_modMult_fast(e2, d1, e0);              /* e2 <-- d1 * e0 */\n    vli_modAdd(e2, e2, t1, curve_p);           /* e2 <-- e2 + t1 */\n    vli_modSquare_fast(f2, e2);                /* f2 <-- e2^2 */\n    vli_modMult_fast(f2, f2, c);               /* f2 <-- f2 * c */\n    vli_modSub_fast(f2, curve_p, f2);          /* f2 <-- p  - f2 */\n    vli_set(d2, t2);                           /* d2 <-- t2 */\n}\n\n/* Routine 3.2.7 RP;  from http://www.nsa.gov/ia/_files/nist-routines.pdf */\nstatic void mod_sqrt_secp224r1_rp(uECC_word_t *d1,\n                                  uECC_word_t *e1,\n                                  uECC_word_t *f1,\n                                  const uECC_word_t *c,\n                                  const uECC_word_t *r) {\n    wordcount_t i;\n    wordcount_t pow2i = 1;\n    uECC_word_t d0[uECC_WORDS];\n    uECC_word_t e0[uECC_WORDS] = {1};          /* e0 <-- 1 */\n    uECC_word_t f0[uECC_WORDS];\n\n    vli_set(d0, r);                            /* d0 <-- r */\n    vli_modSub_fast(f0, curve_p, c);           /* f0 <-- p  - c */\n    for (i = 0; i <= 6; i++) {\n        mod_sqrt_secp224r1_rss(d1, e1, f1, d0, e0, f0, pow2i); /* RSS (d1,e1,f1,d0,e0,f0,2^i) */\n        mod_sqrt_secp224r1_rm(d1, e1, f1, c, d1, e1, d0, e0);  /* RM (d1,e1,f1,c,d1,e1,d0,e0) */\n        vli_set(d0, d1);                       /* d0 <-- d1 */\n        vli_set(e0, e1);                       /* e0 <-- e1 */\n        vli_set(f0, f1);                       /* f0 <-- f1 */\n        pow2i *= 2;\n    }\n}\n\n/* Compute a = sqrt(a) (mod curve_p). */\n/* Routine 3.2.8 mp_mod_sqrt_224; from http://www.nsa.gov/ia/_files/nist-routines.pdf */\nstatic void mod_sqrt(uECC_word_t *a) {\n    bitcount_t i;\n    uECC_word_t e1[uECC_WORDS];\n    uECC_word_t f1[uECC_WORDS];\n    uECC_word_t d0[uECC_WORDS];\n    uECC_word_t e0[uECC_WORDS];\n    uECC_word_t f0[uECC_WORDS];\n    uECC_word_t d1[uECC_WORDS];\n\n    // s = a; using constant instead of random value\n    mod_sqrt_secp224r1_rp(d0, e0, f0, a, a);           /* RP (d0, e0, f0, c, s) */\n    mod_sqrt_secp224r1_rs(d1, e1, f1, d0, e0, f0);     /* RS (d1, e1, f1, d0, e0, f0) */\n    for (i = 1; i <= 95; i++) {\n        vli_set(d0, d1);                               /* d0 <-- d1 */\n        vli_set(e0, e1);                               /* e0 <-- e1 */\n        vli_set(f0, f1);                               /* f0 <-- f1 */\n        mod_sqrt_secp224r1_rs(d1, e1, f1, d0, e0, f0); /* RS (d1, e1, f1, d0, e0, f0) */\n        if (vli_isZero(d1)) {                          /* if d1 == 0 */\n            break;\n        }\n    }\n    vli_modInv(f1, e0, curve_p);                       /* f1 <-- 1 / e0 */\n    vli_modMult_fast(a, d0, f1);                       /* a  <-- d0 / e0 */\n}\n\n#else /* uECC_CURVE */\n\n/* Compute a = sqrt(a) (mod curve_p). */\nstatic void mod_sqrt(uECC_word_t *a) {\n    bitcount_t i;\n    uECC_word_t p1[uECC_WORDS] = {1};\n    uECC_word_t l_result[uECC_WORDS] = {1};\n\n    /* Since curve_p == 3 (mod 4) for all supported curves, we can\n       compute sqrt(a) = a^((curve_p + 1) / 4) (mod curve_p). */\n    vli_add(p1, curve_p, p1); /* p1 = curve_p + 1 */\n    for (i = vli_numBits(p1, uECC_WORDS) - 1; i > 1; --i) {\n        vli_modSquare_fast(l_result, l_result);\n        if (vli_testBit(p1, i)) {\n            vli_modMult_fast(l_result, l_result, a);\n        }\n    }\n    vli_set(a, l_result);\n}\n#endif /* uECC_CURVE */\n\n#if uECC_WORD_SIZE == 1\n\nstatic void vli_nativeToBytes(uint8_t * RESTRICT dest, const uint8_t * RESTRICT src) {\n    uint8_t i;\n    for (i = 0; i < uECC_BYTES; ++i) {\n        dest[i] = src[(uECC_BYTES - 1) - i];\n    }\n}\n\n#define vli_bytesToNative(dest, src) vli_nativeToBytes((dest), (src))\n\n#elif uECC_WORD_SIZE == 4\n\nstatic void vli_nativeToBytes(uint8_t *bytes, const uint32_t *native) {\n    unsigned i;\n    for (i = 0; i < uECC_WORDS; ++i) {\n        uint8_t *digit = bytes + 4 * (uECC_WORDS - 1 - i);\n        digit[0] = native[i] >> 24;\n        digit[1] = native[i] >> 16;\n        digit[2] = native[i] >> 8;\n        digit[3] = native[i];\n    }\n}\n\nstatic void vli_bytesToNative(uint32_t *native, const uint8_t *bytes) {\n    unsigned i;\n    for (i = 0; i < uECC_WORDS; ++i) {\n        const uint8_t *digit = bytes + 4 * (uECC_WORDS - 1 - i);\n        native[i] = ((uint32_t)digit[0] << 24) | ((uint32_t)digit[1] << 16) |\n                    ((uint32_t)digit[2] << 8) | (uint32_t)digit[3];\n    }\n}\n\n#else\n\nstatic void vli_nativeToBytes(uint8_t *bytes, const uint64_t *native) {\n    unsigned i;\n    for (i = 0; i < uECC_WORDS; ++i) {\n        uint8_t *digit = bytes + 8 * (uECC_WORDS - 1 - i);\n        digit[0] = native[i] >> 56;\n        digit[1] = native[i] >> 48;\n        digit[2] = native[i] >> 40;\n        digit[3] = native[i] >> 32;\n        digit[4] = native[i] >> 24;\n        digit[5] = native[i] >> 16;\n        digit[6] = native[i] >> 8;\n        digit[7] = native[i];\n    }\n}\n\nstatic void vli_bytesToNative(uint64_t *native, const uint8_t *bytes) {\n    unsigned i;\n    for (i = 0; i < uECC_WORDS; ++i) {\n        const uint8_t *digit = bytes + 8 * (uECC_WORDS - 1 - i);\n        native[i] = ((uint64_t)digit[0] << 56) | ((uint64_t)digit[1] << 48) |\n                    ((uint64_t)digit[2] << 40) | ((uint64_t)digit[3] << 32) |\n                    ((uint64_t)digit[4] << 24) | ((uint64_t)digit[5] << 16) |\n                    ((uint64_t)digit[6] << 8) | (uint64_t)digit[7];\n    }\n}\n\n#endif /* uECC_WORD_SIZE */\n\nint uECC_make_key(uint8_t public_key[uECC_BYTES*2], uint8_t private_key[uECC_BYTES]) {\n    uECC_word_t private[uECC_WORDS];\n    EccPoint public;\n    uECC_word_t tries;\n    for (tries = 0; tries < MAX_TRIES; ++tries) {\n        if (g_rng_function((uint8_t *)private, sizeof(private)) &&\n                EccPoint_compute_public_key(&public, private)) {\n            vli_nativeToBytes(private_key, private);\n            vli_nativeToBytes(public_key, public.x);\n            vli_nativeToBytes(public_key + uECC_BYTES, public.y);\n            return 1;\n        }\n    }\n    return 0;\n}\n\nint uECC_shared_secret(const uint8_t public_key[uECC_BYTES*2],\n                       const uint8_t private_key[uECC_BYTES],\n                       uint8_t secret[uECC_BYTES]) {\n    EccPoint public;\n    EccPoint product;\n    uECC_word_t private[uECC_WORDS];\n    uECC_word_t tmp[uECC_WORDS];\n    uECC_word_t *p2[2] = {private, tmp};\n    uECC_word_t random[uECC_WORDS];\n    uECC_word_t *initial_Z = 0;\n    uECC_word_t tries;\n    uECC_word_t carry;\n\n    // Try to get a random initial Z value to improve protection against side-channel\n    // attacks. If the RNG fails every time (eg it was not defined), we continue so that\n    // uECC_shared_secret() can still work without an RNG defined.\n    for (tries = 0; tries < MAX_TRIES; ++tries) {\n        if (g_rng_function((uint8_t *)random, sizeof(random)) && !vli_isZero(random)) {\n            initial_Z = random;\n            break;\n        }\n    }\n\n    vli_bytesToNative(private, private_key);\n    vli_bytesToNative(public.x, public_key);\n    vli_bytesToNative(public.y, public_key + uECC_BYTES);\n\n#if (uECC_CURVE == uECC_secp160r1)\n    // Don't regularize the bitcount for secp160r1.\n    EccPoint_mult(&product, &public, private, initial_Z, vli_numBits(private, uECC_WORDS));\n#else\n    // Regularize the bitcount for the private key so that attackers cannot use a side channel\n    // attack to learn the number of leading zeros.\n    carry = vli_add(private, private, curve_n);\n    vli_add(tmp, private, curve_n);\n    EccPoint_mult(&product, &public, p2[!carry], initial_Z, (uECC_BYTES * 8) + 1);\n#endif\n\n    vli_nativeToBytes(secret, product.x);\n    return !EccPoint_isZero(&product);\n}\n\nvoid uECC_compress(const uint8_t public_key[uECC_BYTES*2], uint8_t compressed[uECC_BYTES+1]) {\n    wordcount_t i;\n    for (i = 0; i < uECC_BYTES; ++i) {\n        compressed[i+1] = public_key[i];\n    }\n    compressed[0] = 2 + (public_key[uECC_BYTES * 2 - 1] & 0x01);\n}\n\n/* Computes result = x^3 + ax + b. result must not overlap x. */\nstatic void curve_x_side(uECC_word_t * RESTRICT result, const uECC_word_t * RESTRICT x) {\n#if (uECC_CURVE == uECC_secp256k1)\n    vli_modSquare_fast(result, x); /* r = x^2 */\n    vli_modMult_fast(result, result, x); /* r = x^3 */\n    vli_modAdd(result, result, curve_b, curve_p); /* r = x^3 + b */\n#else\n    uECC_word_t _3[uECC_WORDS] = {3}; /* -a = 3 */\n\n    vli_modSquare_fast(result, x); /* r = x^2 */\n    vli_modSub_fast(result, result, _3); /* r = x^2 - 3 */\n    vli_modMult_fast(result, result, x); /* r = x^3 - 3x */\n    vli_modAdd(result, result, curve_b, curve_p); /* r = x^3 - 3x + b */\n#endif\n}\n\nvoid uECC_decompress(const uint8_t compressed[uECC_BYTES+1], uint8_t public_key[uECC_BYTES*2]) {\n    EccPoint point;\n    vli_bytesToNative(point.x, compressed + 1);\n    curve_x_side(point.y, point.x);\n    mod_sqrt(point.y);\n\n    if ((point.y[0] & 0x01) != (compressed[0] & 0x01)) {\n        vli_sub(point.y, curve_p, point.y);\n    }\n\n    vli_nativeToBytes(public_key, point.x);\n    vli_nativeToBytes(public_key + uECC_BYTES, point.y);\n}\n\nint uECC_valid_public_key(const uint8_t public_key[uECC_BYTES*2]) {\n    uECC_word_t tmp1[uECC_WORDS];\n    uECC_word_t tmp2[uECC_WORDS];\n    EccPoint public;\n\n    vli_bytesToNative(public.x, public_key);\n    vli_bytesToNative(public.y, public_key + uECC_BYTES);\n\n    // The point at infinity is invalid.\n    if (EccPoint_isZero(&public)) {\n        return 0;\n    }\n\n    // x and y must be smaller than p.\n    if (vli_cmp(curve_p, public.x) != 1 || vli_cmp(curve_p, public.y) != 1) {\n        return 0;\n    }\n\n    vli_modSquare_fast(tmp1, public.y); /* tmp1 = y^2 */\n    curve_x_side(tmp2, public.x); /* tmp2 = x^3 + ax + b */\n\n    /* Make sure that y^2 == x^3 + ax + b */\n    return (vli_cmp(tmp1, tmp2) == 0);\n}\n\nint uECC_compute_public_key(const uint8_t private_key[uECC_BYTES],\n                            uint8_t public_key[uECC_BYTES * 2]) {\n    uECC_word_t private[uECC_WORDS];\n    EccPoint public;\n\n    vli_bytesToNative(private, private_key);\n\n    if (!EccPoint_compute_public_key(&public, private)) {\n        return 0;\n    }\n\n    vli_nativeToBytes(public_key, public.x);\n    vli_nativeToBytes(public_key + uECC_BYTES, public.y);\n    return 1;\n}\n\nint uECC_bytes(void) {\n    return uECC_BYTES;\n}\n\nint uECC_curve(void) {\n    return uECC_CURVE;\n}\n\n/* -------- ECDSA code -------- */\n\n#if (uECC_CURVE == uECC_secp160r1)\nstatic void vli_clear_n(uECC_word_t *vli) {\n    vli_clear(vli);\n    vli[uECC_N_WORDS - 1] = 0;\n}\n\nstatic uECC_word_t vli_isZero_n(const uECC_word_t *vli) {\n    if (vli[uECC_N_WORDS - 1]) {\n        return 0;\n    }\n    return vli_isZero(vli);\n}\n\nstatic void vli_set_n(uECC_word_t *dest, const uECC_word_t *src) {\n    vli_set(dest, src);\n    dest[uECC_N_WORDS - 1] = src[uECC_N_WORDS - 1];\n}\n\nstatic cmpresult_t vli_cmp_n(const uECC_word_t *left, const uECC_word_t *right) {\n    if (left[uECC_N_WORDS - 1] > right[uECC_N_WORDS - 1]) {\n        return 1;\n    } else if (left[uECC_N_WORDS - 1] < right[uECC_N_WORDS - 1]) {\n        return -1;\n    }\n    return vli_cmp(left, right);\n}\n\nstatic void vli_rshift1_n(uECC_word_t *vli) {\n    vli_rshift1(vli);\n    vli[uECC_N_WORDS - 2] |= vli[uECC_N_WORDS - 1] << (uECC_WORD_BITS - 1);\n    vli[uECC_N_WORDS - 1] = vli[uECC_N_WORDS - 1] >> 1;\n}\n\nstatic uECC_word_t vli_add_n(uECC_word_t *result,\n                             const uECC_word_t *left,\n                             const uECC_word_t *right) {\n    uECC_word_t carry = vli_add(result, left, right);\n    uECC_word_t sum = left[uECC_N_WORDS - 1] + right[uECC_N_WORDS - 1] + carry;\n    if (sum != left[uECC_N_WORDS - 1]) {\n        carry = (sum < left[uECC_N_WORDS - 1]);\n    }\n    result[uECC_N_WORDS - 1] = sum;\n    return carry;\n}\n\nstatic uECC_word_t vli_sub_n(uECC_word_t *result,\n                             const uECC_word_t *left,\n                             const uECC_word_t *right) {\n    uECC_word_t borrow = vli_sub(result, left, right);\n    uECC_word_t diff = left[uECC_N_WORDS - 1] - right[uECC_N_WORDS - 1] - borrow;\n    if (diff != left[uECC_N_WORDS - 1]) {\n        borrow = (diff > left[uECC_N_WORDS - 1]);\n    }\n    result[uECC_N_WORDS - 1] = diff;\n    return borrow;\n}\n\n#if !muladd_exists\nstatic void muladd(uECC_word_t a,\n                   uECC_word_t b,\n                   uECC_word_t *r0,\n                   uECC_word_t *r1,\n                   uECC_word_t *r2) {\n    uECC_dword_t p = (uECC_dword_t)a * b;\n    uECC_dword_t r01 = ((uECC_dword_t)(*r1) << uECC_WORD_BITS) | *r0;\n    r01 += p;\n    *r2 += (r01 < p);\n    *r1 = r01 >> uECC_WORD_BITS;\n    *r0 = (uECC_word_t)r01;\n}\n#define muladd_exists 1\n#endif\n\nstatic void vli_mult_n(uECC_word_t *result, const uECC_word_t *left, const uECC_word_t *right) {\n    uECC_word_t r0 = 0;\n    uECC_word_t r1 = 0;\n    uECC_word_t r2 = 0;\n    wordcount_t i, k;\n\n    for (k = 0; k < uECC_N_WORDS * 2 - 1; ++k) {\n        wordcount_t min = (k < uECC_N_WORDS ? 0 : (k + 1) - uECC_N_WORDS);\n        wordcount_t max = (k < uECC_N_WORDS ? k : uECC_N_WORDS - 1);\n        for (i = min; i <= max; ++i) {\n            muladd(left[i], right[k - i], &r0, &r1, &r2);\n        }\n        result[k] = r0;\n        r0 = r1;\n        r1 = r2;\n        r2 = 0;\n    }\n    result[uECC_N_WORDS * 2 - 1] = r0;\n}\n\nstatic void vli_modAdd_n(uECC_word_t *result,\n                         const uECC_word_t *left,\n                         const uECC_word_t *right,\n                         const uECC_word_t *mod) {\n    uECC_word_t carry = vli_add_n(result, left, right);\n    if (carry || vli_cmp_n(result, mod) >= 0) {\n        vli_sub_n(result, result, mod);\n    }\n}\n\nstatic void vli_modInv_n(uECC_word_t *result, const uECC_word_t *input, const uECC_word_t *mod) {\n    uECC_word_t a[uECC_N_WORDS], b[uECC_N_WORDS], u[uECC_N_WORDS], v[uECC_N_WORDS];\n    uECC_word_t carry;\n    cmpresult_t cmpResult;\n\n    if (vli_isZero_n(input)) {\n        vli_clear_n(result);\n        return;\n    }\n\n    vli_set_n(a, input);\n    vli_set_n(b, mod);\n    vli_clear_n(u);\n    u[0] = 1;\n    vli_clear_n(v);\n    while ((cmpResult = vli_cmp_n(a, b)) != 0) {\n        carry = 0;\n        if (EVEN(a)) {\n            vli_rshift1_n(a);\n            if (!EVEN(u)) {\n                carry = vli_add_n(u, u, mod);\n            }\n            vli_rshift1_n(u);\n            if (carry) {\n                u[uECC_N_WORDS - 1] |= HIGH_BIT_SET;\n            }\n        } else if (EVEN(b)) {\n            vli_rshift1_n(b);\n            if (!EVEN(v)) {\n                carry = vli_add_n(v, v, mod);\n            }\n            vli_rshift1_n(v);\n            if (carry) {\n                v[uECC_N_WORDS - 1] |= HIGH_BIT_SET;\n            }\n        } else if (cmpResult > 0) {\n            vli_sub_n(a, a, b);\n            vli_rshift1_n(a);\n            if (vli_cmp_n(u, v) < 0) {\n                vli_add_n(u, u, mod);\n            }\n            vli_sub_n(u, u, v);\n            if (!EVEN(u)) {\n                carry = vli_add_n(u, u, mod);\n            }\n            vli_rshift1_n(u);\n            if (carry) {\n                u[uECC_N_WORDS - 1] |= HIGH_BIT_SET;\n            }\n        } else {\n            vli_sub_n(b, b, a);\n            vli_rshift1_n(b);\n            if (vli_cmp_n(v, u) < 0) {\n                vli_add_n(v, v, mod);\n            }\n            vli_sub_n(v, v, u);\n            if (!EVEN(v)) {\n                carry = vli_add_n(v, v, mod);\n            }\n            vli_rshift1_n(v);\n            if (carry) {\n                v[uECC_N_WORDS - 1] |= HIGH_BIT_SET;\n            }\n        }\n    }\n    vli_set_n(result, u);\n}\n\nstatic void vli2_rshift1_n(uECC_word_t *vli) {\n    vli_rshift1_n(vli);\n    vli[uECC_N_WORDS - 1] |= vli[uECC_N_WORDS] << (uECC_WORD_BITS - 1);\n    vli_rshift1_n(vli + uECC_N_WORDS);\n}\n\nstatic uECC_word_t vli2_sub_n(uECC_word_t *result,\n                              const uECC_word_t *left,\n                              const uECC_word_t *right) {\n    uECC_word_t borrow = 0;\n    wordcount_t i;\n    for (i = 0; i < uECC_N_WORDS * 2; ++i) {\n        uECC_word_t diff = left[i] - right[i] - borrow;\n        if (diff != left[i]) {\n            borrow = (diff > left[i]);\n        }\n        result[i] = diff;\n    }\n    return borrow;\n}\n\n/* Computes result = (left * right) % curve_n. */\nstatic void vli_modMult_n(uECC_word_t *result, const uECC_word_t *left, const uECC_word_t *right) {\n    bitcount_t i;\n    uECC_word_t product[2 * uECC_N_WORDS];\n    uECC_word_t modMultiple[2 * uECC_N_WORDS];\n    uECC_word_t tmp[2 * uECC_N_WORDS];\n    uECC_word_t *v[2] = {tmp, product};\n    uECC_word_t index = 1;\n\n    vli_mult_n(product, left, right);\n    vli_clear_n(modMultiple);\n    vli_set(modMultiple + uECC_N_WORDS + 1, curve_n);\n    vli_rshift1(modMultiple + uECC_N_WORDS + 1);\n    modMultiple[2 * uECC_N_WORDS - 1] |= HIGH_BIT_SET;\n    modMultiple[uECC_N_WORDS] = HIGH_BIT_SET;\n\n    for (i = 0;\n         i <= ((((bitcount_t)uECC_N_WORDS) << uECC_WORD_BITS_SHIFT) + (uECC_WORD_BITS - 1));\n         ++i) {\n        uECC_word_t borrow = vli2_sub_n(v[1 - index], v[index], modMultiple);\n        index = !(index ^ borrow); /* Swap the index if there was no borrow */\n        vli2_rshift1_n(modMultiple);\n    }\n    vli_set_n(result, v[index]);\n}\n\n#else\n\n#define vli_cmp_n vli_cmp\n#define vli_modInv_n vli_modInv\n#define vli_modAdd_n vli_modAdd\n\nstatic void vli2_rshift1(uECC_word_t *vli) {\n    vli_rshift1(vli);\n    vli[uECC_WORDS - 1] |= vli[uECC_WORDS] << (uECC_WORD_BITS - 1);\n    vli_rshift1(vli + uECC_WORDS);\n}\n\nstatic uECC_word_t vli2_sub(uECC_word_t *result,\n                            const uECC_word_t *left,\n                            const uECC_word_t *right) {\n    uECC_word_t borrow = 0;\n    wordcount_t i;\n    for (i = 0; i < uECC_WORDS * 2; ++i) {\n        uECC_word_t diff = left[i] - right[i] - borrow;\n        if (diff != left[i]) {\n            borrow = (diff > left[i]);\n        }\n        result[i] = diff;\n    }\n    return borrow;\n}\n\n/* Computes result = (left * right) % curve_n. */\nstatic void vli_modMult_n(uECC_word_t *result, const uECC_word_t *left, const uECC_word_t *right) {\n    uECC_word_t product[2 * uECC_WORDS];\n    uECC_word_t modMultiple[2 * uECC_WORDS];\n    uECC_word_t tmp[2 * uECC_WORDS];\n    uECC_word_t *v[2] = {tmp, product};\n    bitcount_t i;\n    uECC_word_t index = 1;\n\n    vli_mult(product, left, right);\n    vli_set(modMultiple + uECC_WORDS, curve_n); /* works if curve_n has its highest bit set */\n    vli_clear(modMultiple);\n\n    for (i = 0; i <= uECC_BYTES * 8; ++i) {\n        uECC_word_t borrow = vli2_sub(v[1 - index], v[index], modMultiple);\n        index = !(index ^ borrow); /* Swap the index if there was no borrow */\n        vli2_rshift1(modMultiple);\n    }\n    vli_set(result, v[index]);\n}\n#endif /* (uECC_CURVE != uECC_secp160r1) */\n\nstatic int uECC_sign_with_k(const uint8_t private_key[uECC_BYTES],\n                            const uint8_t message_hash[uECC_BYTES],\n                            uECC_word_t k[uECC_N_WORDS],\n                            uint8_t signature[uECC_BYTES*2]) {\n    uECC_word_t tmp[uECC_N_WORDS];\n    uECC_word_t s[uECC_N_WORDS];\n    uECC_word_t *k2[2] = {tmp, s};\n    EccPoint p;\n    uECC_word_t carry;\n    uECC_word_t tries;\n\n    /* Make sure 0 < k < curve_n */\n    if (vli_isZero(k) || vli_cmp_n(curve_n, k) != 1) {\n        return 0;\n    }\n\n#if (uECC_CURVE == uECC_secp160r1)\n    /* Make sure that we don't leak timing information about k.\n       See http://eprint.iacr.org/2011/232.pdf */\n    vli_add_n(tmp, k, curve_n);\n    carry = (tmp[uECC_WORDS] & 0x02);\n    vli_add_n(s, tmp, curve_n);\n\n    /* p = k * G */\n    EccPoint_mult(&p, &curve_G, k2[!carry], 0, (uECC_BYTES * 8) + 2);\n#else\n    /* Make sure that we don't leak timing information about k.\n       See http://eprint.iacr.org/2011/232.pdf */\n    carry = vli_add(tmp, k, curve_n);\n    vli_add(s, tmp, curve_n);\n\n    /* p = k * G */\n    EccPoint_mult(&p, &curve_G, k2[!carry], 0, (uECC_BYTES * 8) + 1);\n\n    /* r = x1 (mod n) */\n    if (vli_cmp(curve_n, p.x) != 1) {\n        vli_sub(p.x, p.x, curve_n);\n    }\n#endif\n    if (vli_isZero(p.x)) {\n        return 0;\n    }\n\n    // Attempt to get a random number to prevent side channel analysis of k.\n    // If the RNG fails every time (eg it was not defined), we continue so that\n    // deterministic signing can still work (with reduced security) without\n    // an RNG defined.\n    carry = 0; // use to signal that the RNG succeeded at least once.\n    for (tries = 0; tries < MAX_TRIES; ++tries) {\n        if (!g_rng_function((uint8_t *)tmp, sizeof(tmp))) {\n            continue;\n        }\n        carry = 1;\n        if (!vli_isZero(tmp)) {\n            break;\n        }\n    }\n    if (!carry) {\n        vli_clear(tmp);\n        tmp[0] = 1;\n    }\n\n    /* Prevent side channel analysis of vli_modInv() to determine\n       bits of k / the private key by premultiplying by a random number */\n    vli_modMult_n(k, k, tmp); /* k' = rand * k */\n    vli_modInv_n(k, k, curve_n); /* k = 1 / k' */\n    vli_modMult_n(k, k, tmp); /* k = 1 / k */\n\n    vli_nativeToBytes(signature, p.x); /* store r */\n\n    tmp[uECC_N_WORDS - 1] = 0;\n    vli_bytesToNative(tmp, private_key); /* tmp = d */\n    s[uECC_N_WORDS - 1] = 0;\n    vli_set(s, p.x);\n    vli_modMult_n(s, tmp, s); /* s = r*d */\n\n    vli_bytesToNative(tmp, message_hash);\n    vli_modAdd_n(s, tmp, s, curve_n); /* s = e + r*d */\n    vli_modMult_n(s, s, k); /* s = (e + r*d) / k */\n#if (uECC_CURVE == uECC_secp160r1)\n    if (s[uECC_N_WORDS - 1]) {\n        return 0;\n    }\n#endif\n    vli_nativeToBytes(signature + uECC_BYTES, s);\n    return 1;\n}\n\nint uECC_sign(const uint8_t private_key[uECC_BYTES],\n              const uint8_t message_hash[uECC_BYTES],\n              uint8_t signature[uECC_BYTES*2]) {\n    uECC_word_t k[uECC_N_WORDS];\n    uECC_word_t tries;\n\n    for (tries = 0; tries < MAX_TRIES; ++tries) {\n        if(g_rng_function((uint8_t *)k, sizeof(k))) {\n        #if (uECC_CURVE == uECC_secp160r1)\n            k[uECC_WORDS] &= 0x01;\n        #endif\n            if (uECC_sign_with_k(private_key, message_hash, k, signature)) {\n                return 1;\n            }\n        }\n    }\n    return 0;\n}\n\n/* Compute an HMAC using K as a key (as in RFC 6979). Note that K is always\n   the same size as the hash result size. */\nstatic void HMAC_init(uECC_HashContext *hash_context, const uint8_t *K) {\n    uint8_t *pad = hash_context->tmp + 2 * hash_context->result_size;\n    unsigned i;\n    for (i = 0; i < hash_context->result_size; ++i)\n        pad[i] = K[i] ^ 0x36;\n    for (; i < hash_context->block_size; ++i)\n        pad[i] = 0x36;\n\n    hash_context->init_hash(hash_context);\n    hash_context->update_hash(hash_context, pad, hash_context->block_size);\n}\n\nstatic void HMAC_update(uECC_HashContext *hash_context,\n                        const uint8_t *message,\n                        unsigned message_size) {\n    hash_context->update_hash(hash_context, message, message_size);\n}\n\nstatic void HMAC_finish(uECC_HashContext *hash_context, const uint8_t *K, uint8_t *result) {\n    uint8_t *pad = hash_context->tmp + 2 * hash_context->result_size;\n    unsigned i;\n    for (i = 0; i < hash_context->result_size; ++i)\n        pad[i] = K[i] ^ 0x5c;\n    for (; i < hash_context->block_size; ++i)\n        pad[i] = 0x5c;\n\n    hash_context->finish_hash(hash_context, result);\n\n    hash_context->init_hash(hash_context);\n    hash_context->update_hash(hash_context, pad, hash_context->block_size);\n    hash_context->update_hash(hash_context, result, hash_context->result_size);\n    hash_context->finish_hash(hash_context, result);\n}\n\n/* V = HMAC_K(V) */\nstatic void update_V(uECC_HashContext *hash_context, uint8_t *K, uint8_t *V) {\n    HMAC_init(hash_context, K);\n    HMAC_update(hash_context, V, hash_context->result_size);\n    HMAC_finish(hash_context, K, V);\n}\n\n/* Deterministic signing, similar to RFC 6979. Differences are:\n    * We just use (truncated) H(m) directly rather than bits2octets(H(m))\n      (it is not reduced modulo curve_n).\n    * We generate a value for k (aka T) directly rather than converting endianness.\n\n   Layout of hash_context->tmp: <K> | <V> | (1 byte overlapped 0x00 or 0x01) / <HMAC pad> */\nint uECC_sign_deterministic(const uint8_t private_key[uECC_BYTES],\n                            const uint8_t message_hash[uECC_BYTES],\n                            uECC_HashContext *hash_context,\n                            uint8_t signature[uECC_BYTES*2]) {\n    uint8_t *K = hash_context->tmp;\n    uint8_t *V = K + hash_context->result_size;\n    uECC_word_t tries;\n    unsigned i;\n    for (i = 0; i < hash_context->result_size; ++i) {\n        V[i] = 0x01;\n        K[i] = 0;\n    }\n\n    // K = HMAC_K(V || 0x00 || int2octets(x) || h(m))\n    HMAC_init(hash_context, K);\n    V[hash_context->result_size] = 0x00;\n    HMAC_update(hash_context, V, hash_context->result_size + 1);\n    HMAC_update(hash_context, private_key, uECC_BYTES);\n    HMAC_update(hash_context, message_hash, uECC_BYTES);\n    HMAC_finish(hash_context, K, K);\n\n    update_V(hash_context, K, V);\n\n    // K = HMAC_K(V || 0x01 || int2octets(x) || h(m))\n    HMAC_init(hash_context, K);\n    V[hash_context->result_size] = 0x01;\n    HMAC_update(hash_context, V, hash_context->result_size + 1);\n    HMAC_update(hash_context, private_key, uECC_BYTES);\n    HMAC_update(hash_context, message_hash, uECC_BYTES);\n    HMAC_finish(hash_context, K, K);\n\n    update_V(hash_context, K, V);\n\n    for (tries = 0; tries < MAX_TRIES; ++tries) {\n        uECC_word_t T[uECC_N_WORDS];\n        uint8_t *T_ptr = (uint8_t *)T;\n        unsigned T_bytes = 0;\n        while (T_bytes < sizeof(T)) {\n            update_V(hash_context, K, V);\n            for (i = 0; i < hash_context->result_size && T_bytes < sizeof(T); ++i, ++T_bytes) {\n                T_ptr[T_bytes] = V[i];\n            }\n        }\n    #if (uECC_CURVE == uECC_secp160r1)\n        T[uECC_WORDS] &= 0x01;\n    #endif\n\n        if (uECC_sign_with_k(private_key, message_hash, T, signature)) {\n            return 1;\n        }\n\n        // K = HMAC_K(V || 0x00)\n        HMAC_init(hash_context, K);\n        V[hash_context->result_size] = 0x00;\n        HMAC_update(hash_context, V, hash_context->result_size + 1);\n        HMAC_finish(hash_context, K, K);\n\n        update_V(hash_context, K, V);\n    }\n    return 0;\n}\n\nstatic bitcount_t smax(bitcount_t a, bitcount_t b) {\n    return (a > b ? a : b);\n}\n\nint uECC_verify(const uint8_t public_key[uECC_BYTES*2],\n                const uint8_t hash[uECC_BYTES],\n                const uint8_t signature[uECC_BYTES*2]) {\n    uECC_word_t u1[uECC_N_WORDS], u2[uECC_N_WORDS];\n    uECC_word_t z[uECC_N_WORDS];\n    EccPoint public, sum;\n    uECC_word_t rx[uECC_WORDS];\n    uECC_word_t ry[uECC_WORDS];\n    uECC_word_t tx[uECC_WORDS];\n    uECC_word_t ty[uECC_WORDS];\n    uECC_word_t tz[uECC_WORDS];\n    const EccPoint *points[4];\n    const EccPoint *point;\n    bitcount_t numBits;\n    bitcount_t i;\n    uECC_word_t r[uECC_N_WORDS], s[uECC_N_WORDS];\n    r[uECC_N_WORDS - 1] = 0;\n    s[uECC_N_WORDS - 1] = 0;\n\n    vli_bytesToNative(public.x, public_key);\n    vli_bytesToNative(public.y, public_key + uECC_BYTES);\n    vli_bytesToNative(r, signature);\n    vli_bytesToNative(s, signature + uECC_BYTES);\n\n    if (vli_isZero(r) || vli_isZero(s)) { /* r, s must not be 0. */\n        return 0;\n    }\n\n#if (uECC_CURVE != uECC_secp160r1)\n    if (vli_cmp(curve_n, r) != 1 || vli_cmp(curve_n, s) != 1) { /* r, s must be < n. */\n        return 0;\n    }\n#endif\n\n    /* Calculate u1 and u2. */\n    vli_modInv_n(z, s, curve_n); /* Z = s^-1 */\n    u1[uECC_N_WORDS - 1] = 0;\n    vli_bytesToNative(u1, hash);\n    vli_modMult_n(u1, u1, z); /* u1 = e/s */\n    vli_modMult_n(u2, r, z); /* u2 = r/s */\n\n    /* Calculate sum = G + Q. */\n    vli_set(sum.x, public.x);\n    vli_set(sum.y, public.y);\n    vli_set(tx, curve_G.x);\n    vli_set(ty, curve_G.y);\n    vli_modSub_fast(z, sum.x, tx); /* Z = x2 - x1 */\n    XYcZ_add(tx, ty, sum.x, sum.y);\n    vli_modInv(z, z, curve_p); /* Z = 1/Z */\n    apply_z(sum.x, sum.y, z);\n\n    /* Use Shamir's trick to calculate u1*G + u2*Q */\n    points[0] = 0;\n    points[1] = &curve_G;\n    points[2] = &public;\n    points[3] = &sum;\n    numBits = smax(vli_numBits(u1, uECC_N_WORDS), vli_numBits(u2, uECC_N_WORDS));\n\n    point = points[(!!vli_testBit(u1, numBits - 1)) | ((!!vli_testBit(u2, numBits - 1)) << 1)];\n    vli_set(rx, point->x);\n    vli_set(ry, point->y);\n    vli_clear(z);\n    z[0] = 1;\n\n    for (i = numBits - 2; i >= 0; --i) {\n        uECC_word_t index;\n        EccPoint_double_jacobian(rx, ry, z);\n\n        index = (!!vli_testBit(u1, i)) | ((!!vli_testBit(u2, i)) << 1);\n        point = points[index];\n        if (point) {\n            vli_set(tx, point->x);\n            vli_set(ty, point->y);\n            apply_z(tx, ty, z);\n            vli_modSub_fast(tz, rx, tx); /* Z = x2 - x1 */\n            XYcZ_add(tx, ty, rx, ry);\n            vli_modMult_fast(z, z, tz);\n        }\n    }\n\n    vli_modInv(z, z, curve_p); /* Z = 1/Z */\n    apply_z(rx, ry, z);\n\n    /* v = x1 (mod n) */\n#if (uECC_CURVE != uECC_secp160r1)\n    if (vli_cmp(curve_n, rx) != 1) {\n        vli_sub(rx, rx, curve_n);\n    }\n#endif\n\n    /* Accept only if v == r. */\n    return vli_equal(rx, r);\n}\n"
  },
  {
    "path": "bluetoe/bindings/nordic/uECC/uECC.h",
    "content": "/* Copyright 2014, Kenneth MacKay. Licensed under the BSD 2-clause license. */\n\n#ifndef _MICRO_ECC_H_\n#define _MICRO_ECC_H_\n\n#include <stdint.h>\n\n/* Platform selection options.\nIf uECC_PLATFORM is not defined, the code will try to guess it based on compiler macros.\nPossible values for uECC_PLATFORM are defined below: */\n#define uECC_arch_other 0\n#define uECC_x86        1\n#define uECC_x86_64     2\n#define uECC_arm        3\n#define uECC_arm_thumb  4\n#define uECC_avr        5\n#define uECC_arm_thumb2 6\n\n/* If desired, you can define uECC_WORD_SIZE as appropriate for your platform (1, 4, or 8 bytes).\nIf uECC_WORD_SIZE is not explicitly defined then it will be automatically set based on your\nplatform. */\n\n/* Inline assembly options.\nuECC_asm_none  - Use standard C99 only.\nuECC_asm_small - Use GCC inline assembly for the target platform (if available), optimized for\n                 minimum size.\nuECC_asm_fast  - Use GCC inline assembly optimized for maximum speed. */\n#define uECC_asm_none  0\n#define uECC_asm_small 1\n#define uECC_asm_fast  2\n#ifndef uECC_ASM\n    #define uECC_ASM uECC_asm_fast\n#endif\n\n/* Curve selection options. */\n#define uECC_secp160r1 1\n#define uECC_secp192r1 2\n#define uECC_secp256r1 3\n#define uECC_secp256k1 4\n#define uECC_secp224r1 5\n#ifndef uECC_CURVE\n    #define uECC_CURVE uECC_secp160r1\n#endif\n\n/* uECC_SQUARE_FUNC - If enabled (defined as nonzero), this will cause a specific function to be\nused for (scalar) squaring instead of the generic multiplication function. This will make things\nfaster by about 8% but increases the code size. */\n#ifndef uECC_SQUARE_FUNC\n    #define uECC_SQUARE_FUNC 1\n#endif\n\n#define uECC_CONCAT1(a, b) a##b\n#define uECC_CONCAT(a, b) uECC_CONCAT1(a, b)\n\n#define uECC_size_1 20 /* secp160r1 */\n#define uECC_size_2 24 /* secp192r1 */\n#define uECC_size_3 32 /* secp256r1 */\n#define uECC_size_4 32 /* secp256k1 */\n#define uECC_size_5 28 /* secp224r1 */\n\n#define uECC_BYTES uECC_CONCAT(uECC_size_, uECC_CURVE)\n\n#ifdef __cplusplus\nextern \"C\"\n{\n#endif\n\n/* uECC_RNG_Function type\nThe RNG function should fill 'size' random bytes into 'dest'. It should return 1 if\n'dest' was filled with random data, or 0 if the random data could not be generated.\nThe filled-in values should be either truly random, or from a cryptographically-secure PRNG.\n\nA correctly functioning RNG function must be set (using uECC_set_rng()) before calling\nuECC_make_key() or uECC_sign().\n\nSetting a correctly functioning RNG function improves the resistance to side-channel attacks\nfor uECC_shared_secret() and uECC_sign_deterministic().\n\nA correct RNG function is set by default when building for Windows, Linux, or OS X.\nIf you are building on another POSIX-compliant system that supports /dev/random or /dev/urandom,\nyou can define uECC_POSIX to use the predefined RNG. For embedded platforms there is no predefined\nRNG function; you must provide your own.\n*/\ntypedef int (*uECC_RNG_Function)(uint8_t *dest, unsigned size);\n\n/* uECC_set_rng() function.\nSet the function that will be used to generate random bytes. The RNG function should\nreturn 1 if the random data was generated, or 0 if the random data could not be generated.\n\nOn platforms where there is no predefined RNG function (eg embedded platforms), this must\nbe called before uECC_make_key() or uECC_sign() are used.\n\nInputs:\n    rng_function - The function that will be used to generate random bytes.\n*/\nvoid uECC_set_rng(uECC_RNG_Function rng_function);\n\n/* uECC_make_key() function.\nCreate a public/private key pair.\n\nOutputs:\n    public_key  - Will be filled in with the public key.\n    private_key - Will be filled in with the private key.\n\nReturns 1 if the key pair was generated successfully, 0 if an error occurred.\n*/\nint uECC_make_key(uint8_t public_key[uECC_BYTES*2], uint8_t private_key[uECC_BYTES]);\n\n/* uECC_shared_secret() function.\nCompute a shared secret given your secret key and someone else's public key.\nNote: It is recommended that you hash the result of uECC_shared_secret() before using it for\nsymmetric encryption or HMAC.\n\nInputs:\n    public_key  - The public key of the remote party.\n    private_key - Your private key.\n\nOutputs:\n    secret - Will be filled in with the shared secret value.\n\nReturns 1 if the shared secret was generated successfully, 0 if an error occurred.\n*/\nint uECC_shared_secret(const uint8_t public_key[uECC_BYTES*2],\n                       const uint8_t private_key[uECC_BYTES],\n                       uint8_t secret[uECC_BYTES]);\n\n/* uECC_sign() function.\nGenerate an ECDSA signature for a given hash value.\n\nUsage: Compute a hash of the data you wish to sign (SHA-2 is recommended) and pass it in to\nthis function along with your private key.\n\nInputs:\n    private_key  - Your private key.\n    message_hash - The hash of the message to sign.\n\nOutputs:\n    signature - Will be filled in with the signature value.\n\nReturns 1 if the signature generated successfully, 0 if an error occurred.\n*/\nint uECC_sign(const uint8_t private_key[uECC_BYTES],\n              const uint8_t message_hash[uECC_BYTES],\n              uint8_t signature[uECC_BYTES*2]);\n\n/* uECC_HashContext structure.\nThis is used to pass in an arbitrary hash function to uECC_sign_deterministic().\nThe structure will be used for multiple hash computations; each time a new hash\nis computed, init_hash() will be called, followed by one or more calls to\nupdate_hash(), and finally a call to finish_hash() to prudoce the resulting hash.\n\nThe intention is that you will create a structure that includes uECC_HashContext\nfollowed by any hash-specific data. For example:\n\ntypedef struct SHA256_HashContext {\n    uECC_HashContext uECC;\n    SHA256_CTX ctx;\n} SHA256_HashContext;\n\nvoid init_SHA256(uECC_HashContext *base) {\n    SHA256_HashContext *context = (SHA256_HashContext *)base;\n    SHA256_Init(&context->ctx);\n}\n\nvoid update_SHA256(uECC_HashContext *base,\n                   const uint8_t *message,\n                   unsigned message_size) {\n    SHA256_HashContext *context = (SHA256_HashContext *)base;\n    SHA256_Update(&context->ctx, message, message_size);\n}\n\nvoid finish_SHA256(uECC_HashContext *base, uint8_t *hash_result) {\n    SHA256_HashContext *context = (SHA256_HashContext *)base;\n    SHA256_Final(hash_result, &context->ctx);\n}\n\n... when signing ...\n{\n    uint8_t tmp[32 + 32 + 64];\n    SHA256_HashContext ctx = {{&init_SHA256, &update_SHA256, &finish_SHA256, 64, 32, tmp}};\n    uECC_sign_deterministic(key, message_hash, &ctx.uECC, signature);\n}\n*/\ntypedef struct uECC_HashContext {\n    void (*init_hash)(struct uECC_HashContext *context);\n    void (*update_hash)(struct uECC_HashContext *context,\n                        const uint8_t *message,\n                        unsigned message_size);\n    void (*finish_hash)(struct uECC_HashContext *context, uint8_t *hash_result);\n    unsigned block_size; /* Hash function block size in bytes, eg 64 for SHA-256. */\n    unsigned result_size; /* Hash function result size in bytes, eg 32 for SHA-256. */\n    uint8_t *tmp; /* Must point to a buffer of at least (2 * result_size + block_size) bytes. */\n} uECC_HashContext;\n\n/* uECC_sign_deterministic() function.\nGenerate an ECDSA signature for a given hash value, using a deterministic algorithm\n(see RFC 6979). You do not need to set the RNG using uECC_set_rng() before calling\nthis function; however, if the RNG is defined it will improve resistance to side-channel\nattacks.\n\nUsage: Compute a hash of the data you wish to sign (SHA-2 is recommended) and pass it in to\nthis function along with your private key and a hash context.\n\nInputs:\n    private_key  - Your private key.\n    message_hash - The hash of the message to sign.\n    hash_context - A hash context to use.\n\nOutputs:\n    signature - Will be filled in with the signature value.\n\nReturns 1 if the signature generated successfully, 0 if an error occurred.\n*/\nint uECC_sign_deterministic(const uint8_t private_key[uECC_BYTES],\n                            const uint8_t message_hash[uECC_BYTES],\n                            uECC_HashContext *hash_context,\n                            uint8_t signature[uECC_BYTES*2]);\n\n/* uECC_verify() function.\nVerify an ECDSA signature.\n\nUsage: Compute the hash of the signed data using the same hash as the signer and\npass it to this function along with the signer's public key and the signature values (r and s).\n\nInputs:\n    public_key - The signer's public key\n    hash       - The hash of the signed data.\n    signature  - The signature value.\n\nReturns 1 if the signature is valid, 0 if it is invalid.\n*/\nint uECC_verify(const uint8_t public_key[uECC_BYTES*2],\n                const uint8_t hash[uECC_BYTES],\n                const uint8_t signature[uECC_BYTES*2]);\n\n/* uECC_compress() function.\nCompress a public key.\n\nInputs:\n    public_key - The public key to compress.\n\nOutputs:\n    compressed - Will be filled in with the compressed public key.\n*/\nvoid uECC_compress(const uint8_t public_key[uECC_BYTES*2], uint8_t compressed[uECC_BYTES+1]);\n\n/* uECC_decompress() function.\nDecompress a compressed public key.\n\nInputs:\n    compressed - The compressed public key.\n\nOutputs:\n    public_key - Will be filled in with the decompressed public key.\n*/\nvoid uECC_decompress(const uint8_t compressed[uECC_BYTES+1], uint8_t public_key[uECC_BYTES*2]);\n\n/* uECC_valid_public_key() function.\nCheck to see if a public key is valid.\n\nNote that you are not required to check for a valid public key before using any other uECC\nfunctions. However, you may wish to avoid spending CPU time computing a shared secret or\nverifying a signature using an invalid public key.\n\nInputs:\n    public_key - The public key to check.\n\nReturns 1 if the public key is valid, 0 if it is invalid.\n*/\nint uECC_valid_public_key(const uint8_t public_key[uECC_BYTES*2]);\n\n/* uECC_compute_public_key() function.\nCompute the corresponding public key for a private key.\n\nInputs:\n    private_key - The private key to compute the public key for\n\nOutputs:\n    public_key - Will be filled in with the corresponding public key\n\nReturns 1 if the key was computed successfully, 0 if an error occurred.\n*/\nint uECC_compute_public_key(const uint8_t private_key[uECC_BYTES],\n                            uint8_t public_key[uECC_BYTES * 2]);\n\n\n/* uECC_bytes() function.\nReturns the value of uECC_BYTES. Helpful for foreign-interfaces to higher-level languages.\n*/\nint uECC_bytes(void);\n\n/* uECC_curve() function.\nReturns the value of uECC_CURVE. Helpful for foreign-interfaces to higher-level languages.\n*/\nint uECC_curve(void);\n\n#ifdef __cplusplus\n} /* end of extern \"C\" */\n#endif\n\n#endif /* _MICRO_ECC_H_ */\n"
  },
  {
    "path": "bluetoe/characteristic.hpp",
    "content": "#ifndef BLUETOE_CHARACTERISTIC_HPP\n#define BLUETOE_CHARACTERISTIC_HPP\n\n#include <bluetoe/characteristic_value.hpp>\n#include <bluetoe/attribute.hpp>\n#include <bluetoe/attribute_handle.hpp>\n#include <bluetoe/codes.hpp>\n#include <bluetoe/uuid.hpp>\n#include <bluetoe/meta_tools.hpp>\n#include <bluetoe/bits.hpp>\n#include <bluetoe/scattered_access.hpp>\n#include <bluetoe/service_uuid.hpp>\n#include <bluetoe/attribute_generator.hpp>\n#include <bluetoe/server_meta_type.hpp>\n#include <bluetoe/meta_types.hpp>\n#include <bluetoe/encryption.hpp>\n#include <bluetoe/descriptor.hpp>\n\n#include <cstddef>\n#include <cassert>\n#include <cstring>\n#include <algorithm>\n#include <type_traits>\n\nnamespace bluetoe {\n\n    namespace details {\n        struct characteristic_uuid_meta_type {};\n\n        struct characteristic_declaration_parameter {};\n        struct characteristic_user_description_parameter {};\n\n        template < typename CCCDIndices, typename ... Options >\n        struct generate_characteristic_attributes;\n\n        template < typename ... Options >\n        struct count_characteristic_attributes;\n\n        template < typename Characteristic >\n        struct sum_by_attributes;\n\n        template < typename Characteristic >\n        struct sum_by_client_configs;\n    }\n\n    /**\n     * @brief a 128-Bit UUID used to identify a characteristic.\n     *\n     * The class takes 5 parameters to store the UUID in the usual form like this:\n     * @code{.cpp}\n     * bluetoe::characteristic_uuid< 0xF0426E52, 0x4450, 0x4F3B, 0xB058, 0x5BAB1191D92A >\n     * @endcode\n     * @sa characteristic\n     */\n    template <\n        std::uint64_t A,\n        std::uint64_t B,\n        std::uint64_t C,\n        std::uint64_t D,\n        std::uint64_t E >\n    struct characteristic_uuid : details::uuid< A, B, C, D, E >\n    {\n        /** @cond HIDDEN_SYMBOLS */\n        struct meta_type :\n            details::characteristic_uuid_meta_type,\n            details::characteristic_value_declaration_parameter,\n            details::characteristic_declaration_parameter,\n            details::valid_characteristic_option_meta_type {};\n        /** @endcond */\n    };\n\n    /**\n     * @brief a 16-Bit UUID used to identify a characteristic.\n     * @sa characteristic\n     */\n    template <\n        std::uint64_t UUID >\n    struct characteristic_uuid16 : details::uuid16< UUID >\n    {\n        /** @cond HIDDEN_SYMBOLS */\n        struct meta_type :\n            details::characteristic_uuid_meta_type,\n            details::characteristic_value_declaration_parameter,\n            details::characteristic_declaration_parameter,\n            details::valid_characteristic_option_meta_type {};\n        static constexpr bool is_128bit = false;\n        /** @endcond */\n    };\n\n    /**\n     * @brief A characteristic is a typed value that is accessable by a GATT client hosted by a GATT server.\n     *\n     * A characteristics type (not it terms of C++ data type) is defined by a UUID. Characteristics with the\n     * same UUID should represent attributes with the same type / characteristic. Usually a GATT client referes\n     * an attribute by its UUID.\n     *\n     * To define the UUID of a characteristic add an instanciated characteristic_uuid<> or characteristic_uuid16<>\n     * type as option to the characteristic.\n     *\n     * For example to define a user defined type to a characteristic:\n     * @code\n     * typedef bluetoe::characteristic<\n     *    bluetoe::characteristic_uuid< 0xF0E6EBE6, 0x3749, 0x41A6, 0xB190, 0x591B262AC20A >\n     * > speed_over_ground_characteristic;\n     * @endcode\n     *\n     * If no UUID is given, bluetoe derives a 128bit UUID from the UUID of the service in which this characteric\n     * is placed in. The first characteristic gets an UUID, where the last bytes are xored with 1, the second\n     * characteristic will get an UUID, where the last bytes are xored with 2 and so on...\n     *\n     * The following examples show a service with the UUID 48B7F909-B039-4550-97AF-336228C45CED and two characteristics,\n     * without an explicit UUID. In this case, the first characteristic becomes the UUID 48B7F909-B039-4550-97AF-336228C45CEC (0x336228C45CED ^ 1 )\n     * and the second UUID becomes the UUID 48B7F909-B039-4550-97AF-336228C45CEF (0x336228C45CED ^ 2 )\n     *\n     * @code\n     * typedef bluetoe::service<\n     *     bluetoe::service_uuid< 0x48B7F909, 0xB039, 0x4550, 0x97AF, 0x336228C45CED >,\n     *     bluetoe::characteristic<\n     *         bluetoe::bind_characteristic_value< std::uint32_t, &presure >,\n     *         bluetoe::no_write_access,\n     *         bluetoe::notify\n     *     >,\n     *     bluetoe::characteristic<\n     *         bluetoe::bind_characteristic_value< std::uint32_t, &alarm_threshold >\n     *     >\n     * > presure_service;\n     * @endcode\n     *\n     * @sa characteristic_uuid\n     * @sa characteristic_uuid16\n     * @sa no_read_access\n     * @sa no_write_access\n     * @sa notify\n     * @sa indicate\n     * @sa higher_outgoing_priority\n     * @sa lower_outgoing_priority\n     * @sa write_without_response\n     * @sa only_write_without_response\n     * @sa bind_characteristic_value\n     * @sa characteristic_name\n     * @sa free_read_blob_handler\n     * @sa free_read_handler\n     * @sa free_write_blob_handler\n     * @sa free_write_handler\n     * @sa mixin_read_handler\n     * @sa mixin_write_handler\n     * @sa mixin_read_blob_handler\n     * @sa mixin_write_blob_handler\n     * @sa mixin_write_indication_control_point_handler\n     * @sa mixin_write_notification_control_point_handler\n     * @sa requires_encryption\n     * @sa no_encryption_required\n     * @sa may_require_encryption\n     * @sa fixed_blob_value\n     * @sa attribute_handle\n     * @sa attribute_handles\n     */\n    template < typename ... Options >\n    class characteristic\n    {\n    public:\n        /** @cond HIDDEN_SYMBOLS */\n\n        using attribute_numbers = details::count_characteristic_attributes< Options... >;\n\n        /**\n         * a characteristic is a list of attributes\n         */\n        static constexpr std::size_t number_of_attributes     = attribute_numbers::number_of_attributes;\n        static constexpr std::size_t number_of_client_configs = attribute_numbers::number_of_client_configs;\n\n        struct meta_type :\n            details::characteristic_meta_type,\n            details::valid_service_option_meta_type {};\n\n\n        // this is just the configured UUID, if auto uuids are used, this will be no_such_type\n        typedef typename details::find_by_meta_type< details::characteristic_uuid_meta_type, Options... >::type configured_uuid;\n\n        /**\n         * @brief gives access to all attributes of the characteristic\n         * @todo remove\n         */\n        template < typename CCCDIndices, std::size_t ClientCharacteristicIndex, typename Service, typename Server >\n        static details::attribute attribute_at( std::size_t index );\n\n        typedef typename details::find_by_meta_type< details::characteristic_value_meta_type, Options... >::type    base_value_type;\n\n        static_assert( !std::is_same< base_value_type, details::no_such_type >::value,\n            \"please make sure, that every characteristic defines some kind of value (bind_characteristic_value<> for example)\" );\n\n        typedef typename base_value_type::template value_impl< Options... >                                         value_type;\n\n        static_assert(\n            std::is_same<\n                typename details::find_by_not_meta_type<\n                    details::valid_characteristic_option_meta_type,\n                    Options...\n                >::type, details::no_such_type >::value,\n            \"Parameter passed to a characteristic that is not a valid characteristic option!\" );\n        /** @endcond */\n    private:\n        // the first two attributes are always the declaration, followed by the value\n        static constexpr std::size_t characteristic_declaration_index = 0;\n        static constexpr std::size_t characteristic_value_index       = 1;\n    };\n\n    /**\n     * @brief adds a name to characteristic\n     *\n     * Adds a \"Characteristic User Description\" to the characteristic. So a GATT client can read the name of the characteristic.\n     *\n     * Example\n     * @code\n    char simple_value = 0;\n    constexpr char name[] = \"This is the name of the characteristic\";\n\n    typedef bluetoe::characteristic<\n        bluetoe::characteristic_name< name >,\n        bluetoe::characteristic_uuid16< 0x0815 >,\n        bluetoe::bind_characteristic_value< char, &simple_value >\n    > named_char;\n     * @endcode\n     */\n    template < const char* const >\n    struct characteristic_name\n    {\n        /** @cond HIDDEN_SYMBOLS */\n        struct meta_type :\n            details::characteristic_parameter_meta_type,\n            details::characteristic_user_description_parameter,\n            details::characteristic_declaration_parameter,\n            details::valid_characteristic_option_meta_type {};\n        /** @endcond */\n    };\n\n    // implementation\n    /** @cond HIDDEN_SYMBOLS */\n\n    template < typename ... Options >\n    template < typename CCCDIndices, std::size_t ClientCharacteristicIndex, typename Service, typename Server >\n    details::attribute characteristic< Options... >::attribute_at( std::size_t index )\n    {\n        assert( index < number_of_attributes );\n\n        using characteristic_descriptor_declarations = typename details::generate_characteristic_attributes< CCCDIndices, Options... >;\n        return characteristic_descriptor_declarations::template attribute_at< ClientCharacteristicIndex, Service, Server >( index );\n    }\n\n    namespace details {\n        template < typename ServiceUUID, typename ... Options >\n        struct characteristic_or_service_uuid\n        {\n            using char_uuid = typename find_by_meta_type< characteristic_uuid_meta_type, Options... >::type;\n            using uuid      = typename or_type< no_such_type, char_uuid, ServiceUUID >::type;\n\n            static_assert( !std::is_same< uuid, no_such_type >::value, \"If instanciating a characteristic<> for testing, please provide a UUID.\" );\n\n            static constexpr bool auto_generated_uuid   = std::is_same< char_uuid, no_such_type >::value;\n            static constexpr bool serice_uuid_is_16_bit = count_by_meta_type< details::service_uuid_16_meta_type, ServiceUUID >::count;\n\n            static_assert( !( auto_generated_uuid && serice_uuid_is_16_bit ), \"No support for automatic generated characteristic UUIDs, if the containing service has not 128 bit UUID\" );\n        };\n\n        /*\n         * Characteristic declaration\n         */\n        template < typename ... AttrOptions, typename CCCDIndices, std::size_t ClientCharacteristicIndex, typename ... ServiceOptions, typename Server, typename ... Options >\n        struct generate_attribute< std::tuple< characteristic_declaration_parameter, AttrOptions... >, CCCDIndices, ClientCharacteristicIndex, service< ServiceOptions...>, Server, Options... >\n        {\n            using characteristic_or_service_uuid_t = characteristic_or_service_uuid< typename service< ServiceOptions... >::uuid, Options... >;\n            using uuid       = typename characteristic_or_service_uuid_t::uuid;\n            using value_type = typename characteristic< Options... >::value_type;\n\n            static void fixup_auto_uuid( details::attribute_access_arguments& args )\n            {\n                using characteristics_t = typename find_all_by_meta_type<\n                    details::characteristic_meta_type,\n                    ServiceOptions... >::type;\n\n                std::uint16_t char_index = index_of< characteristic< Options... >, characteristics_t >::value + 1;\n\n                static constexpr std::size_t uuid_offset = 3;\n\n                int index_low  = static_cast< int >( args.buffer_offset ) - static_cast< int >( uuid_offset );\n                int index_high = static_cast< int >( args.buffer_offset ) - static_cast< int >( uuid_offset + 1 );\n\n                if ( index_low >= 0 && index_low < static_cast< int >( args.buffer_size ) )\n                    args.buffer[ index_low ] ^= ( char_index & 0xff );\n\n                if ( index_high >= 0 && index_high < static_cast< int >( args.buffer_size ) )\n                    args.buffer[ index_high ] ^= ( char_index >> 8 );\n            }\n\n            /*\n             * the characteristic decalarion consists of 3 parts: a Properties byte, two bytes value handle and 2 or 16 bytes UUID\n             */\n            static details::attribute_access_result char_declaration_access( details::attribute_access_arguments& args, std::size_t attribute_index )\n            {\n                if ( args.type != details::attribute_access_type::read )\n                    return details::attribute_access_result::write_not_permitted;\n\n                static constexpr bool has_write_attribute_ =\n                    value_type::has_write_access && !value_type::has_only_write_without_response;\n                static constexpr bool has_write_without_response_attribute =\n                    value_type::has_only_write_without_response || value_type::has_write_without_response;\n\n                const std::uint8_t properties[] = {\n                    static_cast< std::uint8_t >(\n                        ( value_type::has_read_access  ? bits( details::gatt_characteristic_properties::read ) : 0 ) |\n                        ( has_write_attribute_         ? bits( details::gatt_characteristic_properties::write ) : 0 ) |\n                        ( has_write_without_response_attribute ? bits( details::gatt_characteristic_properties::write_without_response ) : 0 ) |\n                        ( value_type::has_notification ? bits( details::gatt_characteristic_properties::notify ) : 0 ) |\n                        ( value_type::has_indication   ? bits( details::gatt_characteristic_properties::indicate ) : 0 ) )\n                };\n\n                const std::uint16_t value_attribute_handle = handle_index_mapping< Server >::handle_by_index( attribute_index + 1 );\n                assert( value_attribute_handle != details::invalid_attribute_handle );\n\n                const std::uint8_t value_handle[] = {\n                    static_cast< std::uint8_t >( value_attribute_handle & 0xff ),\n                    static_cast< std::uint8_t >( value_attribute_handle >> 8 )\n                };\n\n                static constexpr auto data_size = sizeof( properties ) + sizeof( value_handle ) + sizeof( uuid::bytes );\n\n                if ( args.buffer_offset > data_size )\n                    return details::attribute_access_result::invalid_offset;\n\n                details::scattered_read_access( args.buffer_offset, properties, value_handle, uuid::bytes, args.buffer, args.buffer_size );\n\n                if ( characteristic_or_service_uuid_t::auto_generated_uuid )\n                    fixup_auto_uuid( args );\n\n                args.buffer_size = std::min< std::size_t >( data_size - args.buffer_offset, args.buffer_size );\n\n                return details::attribute_access_result::success;\n            }\n\n            static const attribute attr;\n        };\n\n        template < typename ... AttrOptions, typename CCCDIndices, std::size_t ClientCharacteristicIndex, typename ... ServiceOptions, typename Server, typename ... Options >\n        const attribute generate_attribute< std::tuple< characteristic_declaration_parameter, AttrOptions... >, CCCDIndices, ClientCharacteristicIndex, service< ServiceOptions... > , Server, Options... >::attr {\n            bits( details::gatt_uuids::characteristic ),\n            &generate_attribute< std::tuple< characteristic_declaration_parameter, AttrOptions... >, CCCDIndices, ClientCharacteristicIndex, service< ServiceOptions... >, Server, Options... >::char_declaration_access\n        };\n\n        /*\n         * Characteristic Value\n         */\n        template < typename ... AttrOptions, typename CCCDIndices, std::size_t ClientCharacteristicIndex, typename Service, typename Server, typename ... Options >\n        struct generate_attribute< std::tuple< characteristic_value_declaration_parameter, AttrOptions... >, CCCDIndices, ClientCharacteristicIndex, Service, Server, Options... >\n        {\n            // the characterist value has two configurable aspects: the uuid and the value. The value is defined in the charcteristic\n            typedef typename characteristic_or_service_uuid< typename Service::uuid, Options... >::uuid      uuid;\n            using char_t = characteristic< Options... >;\n            static constexpr bool requires_encryption = characteristic_requires_encryption< char_t, Service, Server >::value;\n\n            static const attribute attr;\n        };\n\n        template < typename ... AttrOptions, typename CCCDIndices, std::size_t ClientCharacteristicIndex, typename Service, typename Server, typename ... Options >\n        const attribute generate_attribute< std::tuple< characteristic_value_declaration_parameter, AttrOptions... >, CCCDIndices, ClientCharacteristicIndex, Service, Server, Options... >::attr {\n            uuid::is_128bit\n                ? bits( details::gatt_uuids::internal_128bit_uuid )\n                : uuid::as_16bit(),\n            &characteristic< Options... >::value_type::template characteristic_value_access< Server, ClientCharacteristicIndex, requires_encryption >\n        };\n\n        /*\n         * Characteristic User Description\n         */\n        template < const char* const Name, typename CCCDIndices, std::size_t ClientCharacteristicIndex, typename Service, typename Server, typename ... Options >\n        struct generate_attribute< std::tuple< characteristic_user_description_parameter, characteristic_name< Name > >, CCCDIndices, ClientCharacteristicIndex, Service, Server, Options... >\n        {\n            static const attribute attr;\n\n            static details::attribute_access_result access( attribute_access_arguments& args, std::size_t )\n            {\n                const std::size_t str_len   = std::strlen( Name );\n\n                if ( args.buffer_offset > str_len )\n                    return details::attribute_access_result::invalid_offset;\n\n                details::attribute_access_result result = attribute_access_result::write_not_permitted;\n\n                if ( args.type == attribute_access_type::read )\n                {\n                    const std::size_t read_size = std::min( args.buffer_size, str_len - args.buffer_offset );\n\n                    std::copy( Name + args.buffer_offset, Name + args.buffer_offset + read_size, args.buffer );\n\n                    result = attribute_access_result::success;\n\n                    args.buffer_size = read_size;\n                }\n\n                return result;\n            }\n\n        };\n\n        template < const char* const Name, typename CCCDIndices, std::size_t ClientCharacteristicIndex, typename Service, typename Server, typename ... Options >\n        const attribute generate_attribute< std::tuple< characteristic_user_description_parameter, characteristic_name< Name > >, CCCDIndices, ClientCharacteristicIndex, Service, Server, Options... >::attr {\n            bits( gatt_uuids::characteristic_user_description ),\n            &generate_attribute< std::tuple< characteristic_user_description_parameter, characteristic_name< Name > >, CCCDIndices, ClientCharacteristicIndex, Service, Server, Options... >::access\n        };\n\n        /*\n         * Client Characteristic Configuration Descriptor (CCCD)\n         */\n        template < typename ... AttrOptions, typename CCCDIndices, std::size_t ClientCharacteristicIndex, typename Service, typename Server, typename ... Options >\n        struct generate_attribute< std::tuple< client_characteristic_configuration_parameter, AttrOptions... >, CCCDIndices, ClientCharacteristicIndex, Service, Server, Options... >\n        {\n            static const attribute attr;\n            using uuid   = typename characteristic_or_service_uuid< typename Service::uuid, Options... >::uuid;\n\n            using char_t = characteristic< Options... >;\n            static constexpr bool requires_encryption = characteristic_requires_encryption< char_t, Service, Server >::value;\n\n            static details::attribute_access_result access( attribute_access_arguments& args, std::size_t )\n            {\n                const auto security_result = details::encryption_requirements< requires_encryption >::check( args.connection_security );\n\n                if ( security_result != details::attribute_access_result::success )\n                    return security_result;\n\n                static constexpr std::size_t flags_size = 2;\n                std::uint8_t buffer[ flags_size ];\n\n                if ( args.buffer_offset > flags_size )\n                    return details::attribute_access_result::invalid_offset;\n\n                details::attribute_access_result result = attribute_access_result::write_not_permitted;\n\n                // currently, a lot of test code supplies an empty CCCDIndices list. In this case, use the ClientCharacteristicIndex\n                const std::size_t cccd_position_index = index_of< std::integral_constant< std::size_t, ClientCharacteristicIndex >, CCCDIndices >::value;\n                const std::size_t cccd_position = std::tuple_size< CCCDIndices >::value == 0\n                                                    ? ClientCharacteristicIndex\n                                                    : cccd_position_index;\n\n                if ( args.type == attribute_access_type::read )\n                {\n                    write_16bit( &buffer[ 0 ], args.client_config.flags( cccd_position ) );\n\n                    const std::size_t read_size = std::min( args.buffer_size, flags_size - args.buffer_offset );\n\n                    std::copy( &buffer[ args.buffer_offset ], &buffer[ args.buffer_offset + read_size ], args.buffer );\n\n                    result = attribute_access_result::success;\n\n                    args.buffer_size = read_size;\n                }\n                else if ( args.type == attribute_access_type::write )\n                {\n                    if ( args.buffer_size + args.buffer_offset > flags_size )\n                        return details::attribute_access_result::invalid_attribute_value_length;\n\n                    if ( args.buffer_offset == 0 )\n                    {\n                        const std::uint16_t old_config = args.client_config.flags( cccd_position );\n                        std::uint8_t serialized_value[ flags_size ];\n                        write_16bit( &serialized_value[ 0 ], old_config );\n\n                        const std::size_t write_size = std::min( args.buffer_size, flags_size - args.buffer_offset );\n                        std::copy( &args.buffer[ args.buffer_offset ], &args.buffer[ args.buffer_offset + write_size ], serialized_value );\n\n                        args.client_config.flags( cccd_position, read_16bit( &serialized_value[ 0 ] ) );\n\n                        using subscription_callback =\n                            typename find_by_meta_type<\n                                characteristic_subscription_call_back_meta_type,\n                                Options..., default_on_characteristic_subscription >::type;\n\n                        subscription_callback::template on_subscription< uuid >(\n                            args.client_config.flags( cccd_position ),\n                            *static_cast< Server* >( args.server ) );\n\n                        if ( old_config != args.client_config.flags( cccd_position ) )\n                            static_cast< Server* >( args.server )->notification_subscription_changed( args.client_config );\n                    }\n\n                    result = attribute_access_result::success;\n                }\n\n                return result;\n            }\n        };\n\n        template < typename ... AttrOptions, typename CCCDIndices, std::size_t ClientCharacteristicIndex, typename Service, typename Server, typename ... Options >\n        constexpr attribute generate_attribute< std::tuple< client_characteristic_configuration_parameter, AttrOptions... >, CCCDIndices, ClientCharacteristicIndex, Service, Server, Options... >::attr {\n            bits( gatt_uuids::client_characteristic_configuration ),\n            &generate_attribute< std::tuple< client_characteristic_configuration_parameter, AttrOptions... >, CCCDIndices, ClientCharacteristicIndex, Service, Server, Options... >::access\n        };\n\n        /*\n         * User Defined Descriptors\n         */\n        template < std::uint16_t UUID, const std::uint8_t* const Value, std::size_t Size, typename CCCDIndices, std::size_t ClientCharacteristicIndex, typename Service, typename Server, typename ... Options >\n        struct generate_attribute< std::tuple< descriptor_parameter, descriptor< UUID, Value, Size > >, CCCDIndices, ClientCharacteristicIndex, Service, Server, Options... >\n        {\n            static const attribute attr;\n\n            static details::attribute_access_result access( attribute_access_arguments& args, std::size_t )\n            {\n                if ( args.type != attribute_access_type::read )\n                    return attribute_access_result::write_not_permitted;\n\n                if ( args.buffer_offset > Size )\n                    return details::attribute_access_result::invalid_offset;\n\n                const std::size_t read_size = std::min( args.buffer_size, Size - args.buffer_offset );\n\n                std::copy( Value + args.buffer_offset, Value + args.buffer_offset + read_size, args.buffer );\n                args.buffer_size = read_size;\n\n                return attribute_access_result::success;\n            }\n\n        };\n\n        template < std::uint16_t UUID, const std::uint8_t* const Value, std::size_t Size, typename CCCDIndices, std::size_t ClientCharacteristicIndex, typename Service, typename Server, typename ... Options >\n        constexpr attribute generate_attribute< std::tuple< descriptor_parameter, descriptor< UUID, Value, Size > >, CCCDIndices, ClientCharacteristicIndex, Service, Server, Options... >::attr {\n            UUID,\n            &generate_attribute< std::tuple< descriptor_parameter, descriptor< UUID, Value, Size > >, CCCDIndices, ClientCharacteristicIndex, Service, Server, Options... >::access\n        };\n\n        template < typename CCCDIndices, typename ... Options >\n        struct generate_characteristic_attributes : generate_attributes<\n                std::tuple< Options... >,\n                std::tuple<\n                    // The order of this list defines the order of the attributes in the characteristic\n                    // Other attribute_handle<> and attribute_handles<> depend on this order.\n                    characteristic_declaration_parameter,\n                    characteristic_value_declaration_parameter,\n                    client_characteristic_configuration_parameter,\n                    characteristic_user_description_parameter,\n                    descriptor_parameter\n                >,\n                CCCDIndices,\n                // force the existens of an characteristic declaration, even without Options with this meta_type\n                std::tuple< empty_meta_type< characteristic_declaration_parameter > >\n            > {};\n\n        template < typename ... Options >\n        struct count_characteristic_attributes\n        {\n            enum { number_of_client_configs =\n                count_by_meta_type< client_characteristic_configuration_parameter, Options... >::count != 0 ? 1 : 0 };\n\n            enum { number_of_user_descriptions =\n                count_by_meta_type< characteristic_user_description_parameter, Options... >::count != 0 ? 1 : 0 };\n\n            enum { number_of_descriptors =\n                count_by_meta_type< descriptor_parameter, Options...>::count };\n\n            enum { number_of_attributes = 2 + number_of_client_configs + number_of_user_descriptions + number_of_descriptors };\n        };\n\n        template < typename Characteristic >\n        struct sum_by_attributes\n        {\n            enum { value = Characteristic::number_of_attributes };\n        };\n\n        template < typename Characteristic >\n        struct sum_by_client_configs\n        {\n            enum { value = Characteristic::number_of_client_configs };\n        };\n\n        /** @endcond */\n    }\n}\n\n#endif\n"
  },
  {
    "path": "bluetoe/characteristic_value.hpp",
    "content": "#ifndef BLUETOE_CHARACTERISTIC_VALUE_HPP\n#define BLUETOE_CHARACTERISTIC_VALUE_HPP\n\n#include <bluetoe/meta_tools.hpp>\n#include <bluetoe/attribute.hpp>\n#include <bluetoe/codes.hpp>\n#include <bluetoe/meta_types.hpp>\n#include <type_traits>\n#include <climits>\n#include <cstring>\n\nnamespace bluetoe {\n\n    namespace details {\n        // type defines the value of a characteristic\n        struct characteristic_value_meta_type {};\n        // type is a valid parameter to a characteristic\n        struct characteristic_parameter_meta_type {};\n        // type is a characteristic read handler\n        struct characteristic_value_read_handler_meta_type {};\n        // type is a characteristic write handler\n        struct characteristic_value_write_handler_meta_type {};\n\n        struct characteristic_value_declaration_parameter {};\n        struct client_characteristic_configuration_parameter {};\n        struct characteristic_subscription_call_back_meta_type {};\n    }\n\n    /**\n     * @brief if added as option to a characteristic, read access is removed from the characteristic\n     *\n     * Even if read access was the only remaining access type, the characterist will not be readable.\n     *\n     * Example:\n     * @code\n        std::uint32_t simple_value = 0xaabbccdd;\n\n        bluetoe::characteristic<\n            bluetoe::characteristic_uuid< 0xD0B10674, 0x6DDD, 0x4B59, 0x89CA, 0xA009B78C956B >,\n            bluetoe::bind_characteristic_value< std::uint32_t, &simple_value >,\n            bluetoe::no_read_access,\n            bluetoe::notify\n        >\n     * @endcode\n     * @sa characteristic\n     */\n    struct no_read_access {\n        /** @cond HIDDEN_SYMBOLS */\n        using meta_type = details::valid_characteristic_option_meta_type;\n        /** @endcond */\n    };\n\n    /**\n     * @brief if added as option to a characteristic, write access is removed from the characteristic\n     *\n     * Even if write access was the only remaining access type, the characterist will not be writeable.\n     *\n     * Example:\n     * @code\n        std::uint32_t simple_value = 0xaabbccdd;\n\n        bluetoe::characteristic<\n            bluetoe::characteristic_uuid< 0xD0B10674, 0x6DDD, 0x4B59, 0x89CA, 0xA009B78C956B >,\n            bluetoe::bind_characteristic_value< std::uint32_t, &simple_value >,\n            bluetoe::no_write_access > >\n     * @endcode\n     * @sa characteristic\n     */\n    struct no_write_access {\n        /** @cond HIDDEN_SYMBOLS */\n        using meta_type = details::valid_characteristic_option_meta_type;\n        /** @endcond */\n    };\n\n    /**\n     * @brief adds the ability to notify this characteristic.\n     *\n     * When a characteristic gets notified, the current value of the characteristic will be send to all\n     * connected clients that have subscribed for notifications. To send a notification, server::notify() have\n     * to be called. The server will store that there is a pending need to send out a notification and will do\n     * so, as soon as there is a free link layer PDU that can be used to transport the notification. The server\n     * will use what ever mean is implemented to read the characteristic, to get the characteristic value.\n     *\n     * @sa server::notify\n     * @sa higher_outgoing_priority\n     * @sa lower_outgoing_priority\n     * @sa indicate\n     */\n    struct notify {\n        /** @cond HIDDEN_SYMBOLS */\n        struct meta_type :\n            details::client_characteristic_configuration_parameter,\n            details::characteristic_parameter_meta_type,\n            details::valid_characteristic_option_meta_type {};\n        /** @endcond */\n    };\n\n    /**\n     * @brief adds the ability to indicate this characteristic.\n     *\n     * When a characteristic gets notified, the current value of the characteristic will be send to all\n     * connected clients that have subscribed for indications.\n     * The difference to notify is, that indication needs to be confirmed by the GATT client.\n     *\n     * @sa server::indicate\n     * @sa higher_outgoing_priority\n     * @sa lower_outgoing_priority\n     * @sa notify\n     */\n    struct indicate {\n        /** @cond HIDDEN_SYMBOLS */\n        struct meta_type :\n            details::client_characteristic_configuration_parameter,\n            details::characteristic_parameter_meta_type,\n            details::valid_characteristic_option_meta_type {};\n        /** @endcond */\n    };\n\n    /**\n     * @brief queues a notification of a characteristic as soon, as it was configured for notification.\n     *\n     * This requires, that the characteristic was configured for notifications.\n     *\n     * @sa characteristic\n     * @sa notify\n     */\n    struct notify_on_subscription {\n        /** @cond HIDDEN_SYMBOLS */\n        template < typename UUID, typename Server >\n        static void on_subscription( std::uint16_t flags, Server& srv )\n        {\n            if ( flags & details::client_characteristic_configuration_notification_enabled )\n                srv.template notify< UUID >();\n        }\n\n        struct meta_type :\n            details::characteristic_subscription_call_back_meta_type,\n            details::characteristic_parameter_meta_type,\n            details::valid_characteristic_option_meta_type {};\n        /** @endcond */\n    };\n\n    /**\n     * @brief queues a indication of a characteristic as soon, as it was configured for indication.\n     *\n     * This requires, that the characteristic was configured for indications.\n     *\n     * @sa characteristic\n     * @sa indicate\n     */\n    struct indicate_on_subscription {\n        /** @cond HIDDEN_SYMBOLS */\n        template < typename UUID, typename Server >\n        static void on_subscription( std::uint16_t flags, Server& srv )\n        {\n            if ( flags & details::client_characteristic_configuration_indication_enabled )\n                srv.template indicate< UUID >();\n        }\n\n        struct meta_type :\n            details::characteristic_subscription_call_back_meta_type,\n            details::characteristic_parameter_meta_type,\n            details::valid_characteristic_option_meta_type {};\n        /** @endcond */\n    };\n\n    /** @cond HIDDEN_SYMBOLS */\n    struct default_on_characteristic_subscription {\n        template < typename UUID, typename Server >\n        static void on_subscription( std::uint16_t, Server& ) {}\n\n        struct meta_type :\n            details::characteristic_subscription_call_back_meta_type,\n            details::characteristic_parameter_meta_type,\n            details::valid_characteristic_option_meta_type {};\n    };\n    /** @endcond */\n\n    /**\n     * @brief sets the Write Without Response Characteristic Property bit.\n     *\n     * By adding this bit to the Characteristic Properties, a client knows that it can use the\n     * Write Without Response sub-procedure. In this case, a client can write to a characteristic\n     * and will get no response from the GATT server. Don't use this property if there is any\n     * need to respond with an error to a write attempt.\n     *\n     * @sa only_write_without_response\n     * @sa characteristic\n     */\n    struct write_without_response {\n        /** @cond HIDDEN_SYMBOLS */\n        struct meta_type :\n            details::characteristic_parameter_meta_type,\n            details::valid_characteristic_option_meta_type {};\n        /** @endcond */\n    };\n\n    /**\n     * @brief set only the Write Without Response Characteristic Property bit.\n     *\n     * Set the Write Without Response Characteristic property and resets the\n     * Write property of the given characteristic.\n     *\n     * @sa write_without_response\n     * @sa characteristic\n     */\n    struct only_write_without_response {\n        /** @cond HIDDEN_SYMBOLS */\n        struct meta_type :\n            details::characteristic_parameter_meta_type,\n            details::valid_characteristic_option_meta_type {};\n        /** @endcond */\n    };\n\n    namespace details {\n        template < bool RequiresEncryption >\n        struct encryption_requirements;\n\n        template <>\n        struct encryption_requirements< false > {\n            static attribute_access_result check( const connection_security_attributes& ) {\n                return attribute_access_result::success;\n            }\n        };\n\n        template <>\n        struct encryption_requirements< true > {\n            static attribute_access_result check( const connection_security_attributes& attr )\n            {\n                if ( attr.is_encrypted )\n                    return attribute_access_result::success;\n\n                return attr.pairing_status == device_pairing_status::no_key\n                    ? attribute_access_result::insufficient_authentication\n                    : attribute_access_result::insufficient_encryption;\n            }\n        };\n\n        /*\n         * Base for value_implementations, providing common attributes and tests\n         */\n        template < typename ... Options >\n        struct value_impl_base\n        {\n           static constexpr bool has_only_write_without_response = details::has_option< only_write_without_response, Options... >::value;\n        };\n    }\n\n    /**\n     * @brief a very simple device to bind a characteristic to a global variable to provide access to the characteristic value\n     */\n    template < typename T, T* Ptr >\n    class bind_characteristic_value\n    {\n    public:\n        /**\n         * @cond HIDDEN_SYMBOLS\n         * use a new type to mixin the options given to characteristic\n         */\n        template < typename ... Options >\n        class value_impl : public details::value_impl_base< Options... >\n        {\n        public:\n            static constexpr bool has_read_access  = !details::has_option< no_read_access, Options... >::value;\n            static constexpr bool has_write_access = !std::is_const< T >::value && !details::has_option< no_write_access, Options... >::value;\n            static constexpr bool has_write_without_response = details::has_option< write_without_response, Options... >::value;\n            static constexpr bool has_notification = details::has_option< notify, Options... >::value;\n            static constexpr bool has_indication   = details::has_option< indicate, Options... >::value;\n\n            template < class Server, std::size_t ClientCharacteristicIndex, bool RequiresEncryption >\n            static details::attribute_access_result characteristic_value_access( details::attribute_access_arguments& args, std::size_t )\n            {\n                const auto security_result = details::encryption_requirements< RequiresEncryption >::check( args.connection_security );\n\n                if ( security_result != details::attribute_access_result::success )\n                    return security_result;\n\n                if ( args.type == details::attribute_access_type::read )\n                {\n                    return characteristic_value_read_access( args, std::integral_constant< bool, has_read_access >() );\n                }\n                else if ( args.type == details::attribute_access_type::write )\n                {\n                    return characteristic_value_write_access( args, std::integral_constant< bool, has_write_access >() );\n                }\n\n                return details::attribute_access_result::write_not_permitted;\n            }\n\n            /*\n             * Used to find this characteristic for notification\n             */\n            static constexpr bool is_this( const void* value )\n            {\n                return value == Ptr;\n            }\n\n        private:\n            static constexpr details::attribute_access_result characteristic_value_read_access( details::attribute_access_arguments& args, const std::true_type& )\n            {\n                return details::attribute_value_read_access( args, static_cast< const std::uint8_t* >( static_cast< const void* >( Ptr ) ), sizeof( T ) );\n            }\n\n            static constexpr details::attribute_access_result characteristic_value_read_access( details::attribute_access_arguments&, const std::false_type& )\n            {\n                return details::attribute_access_result::read_not_permitted;\n            }\n\n            static details::attribute_access_result characteristic_value_write_access( details::attribute_access_arguments& args, const std::true_type& )\n            {\n                if ( args.buffer_offset > sizeof( T ) )\n                    return details::attribute_access_result::invalid_offset;\n\n                if ( args.buffer_size + args.buffer_offset > sizeof( T ) )\n                    return details::attribute_access_result::invalid_attribute_value_length;\n\n                args.buffer_size = std::min< std::size_t >( args.buffer_size, sizeof( T ) - args.buffer_offset );\n\n                std::uint8_t* const ptr = static_cast< std::uint8_t* >( static_cast< void* >( Ptr ) );\n                std::copy( args.buffer, args.buffer + args.buffer_size, ptr + args.buffer_offset );\n\n                return details::attribute_access_result::success;\n            }\n\n            static constexpr details::attribute_access_result characteristic_value_write_access( details::attribute_access_arguments&, const std::false_type& )\n            {\n                return details::attribute_access_result::write_not_permitted;\n            }\n\n        };\n\n        struct meta_type :\n            details::characteristic_value_meta_type,\n            details::characteristic_value_declaration_parameter,\n            details::valid_characteristic_option_meta_type {};\n        /** @endcond */\n    };\n\n    /**\n     * @brief provides a characteristic with a fixed, read-only value\n     *\n     * Implements a numeric, readable litte endian encoded integer value.\n     */\n    template < class T, T Value >\n    struct fixed_value {\n        /**\n         * @cond HIDDEN_SYMBOLS\n         */\n        template < typename ... Options >\n        class value_impl : public details::value_impl_base< Options... >\n        {\n        public:\n            static constexpr bool has_read_access  = !details::has_option< no_read_access, Options... >::value;\n            static constexpr bool has_write_access = false;\n            static constexpr bool has_write_without_response = false;\n            static constexpr bool has_notification = details::has_option< notify, Options... >::value;\n            static constexpr bool has_indication   = details::has_option< indicate, Options... >::value;\n\n            template < class Server, std::size_t ClientCharacteristicIndex, bool RequiresEncryption  >\n            static details::attribute_access_result characteristic_value_access( details::attribute_access_arguments& args, std::size_t )\n            {\n                const auto security_result = details::encryption_requirements< RequiresEncryption >::check( args.connection_security );\n\n                if ( security_result != details::attribute_access_result::success )\n                    return security_result;\n\n                if ( !has_read_access )\n                    return details::attribute_access_result::read_not_permitted;\n\n                if ( args.type != details::attribute_access_type::read )\n                    return details::attribute_access_result::write_not_permitted;\n\n                if ( args.buffer_offset > sizeof( T ) )\n                    return details::attribute_access_result::invalid_offset;\n\n                args.buffer_size = std::min< std::size_t >( args.buffer_size, sizeof( T ) - args.buffer_offset );\n\n                // copy data\n                std::uint8_t* output = args.buffer;\n                for ( auto i = args.buffer_offset; i != args.buffer_offset + args.buffer_size; ++i, ++output )\n                    *output = ( Value >> ( 8 * i ) ) & 0xff;\n\n                return details::attribute_access_result::success;\n            }\n\n            static constexpr bool is_this( const void* )\n            {\n                return false;\n            }\n        };\n\n        struct meta_type :\n            details::characteristic_value_meta_type,\n            details::characteristic_value_declaration_parameter,\n            details::valid_characteristic_option_meta_type {};\n        /** @endcond */\n    };\n\n    /**\n     * @brief fixed size 8 bit unsigned int characteristic value\n     * @sa fixed_value\n     */\n    template < std::uint8_t Value >\n    using fixed_uint8_value = fixed_value< std::uint8_t, Value >;\n\n    /**\n     * @brief fixed size 16 bit unsigned int characteristic value\n     * @sa fixed_value\n     */\n    template < std::uint16_t Value >\n    using fixed_uint16_value = fixed_value< std::uint16_t, Value >;\n\n\n    /**\n     * @brief fixed size 32 bit unsigned int characteristic value\n     * @sa fixed_value\n     */\n    template < std::uint32_t Value >\n    using fixed_uint32_value = fixed_value< std::uint32_t, Value >;\n\n    /**\n     * @brief a constant string characteristic value\n     *\n     * The type Text have to have a member value() that returns a const char* or a const std::uint8_t*\n     * and a member size() that returns the length of the data.\n     */\n    template < class Text >\n    struct cstring_wrapper\n    {\n        /**\n         * @cond HIDDEN_SYMBOLS\n         */\n        template < typename ... Options >\n        class value_impl : public details::value_impl_base< Options... >\n        {\n        public:\n            static constexpr bool has_read_access  = true;\n            static constexpr bool has_write_access = false;\n            static constexpr bool has_write_without_response = false;\n            static constexpr bool has_notification = false;\n            static constexpr bool has_indication   = false;\n\n            template < class Server, std::size_t ClientCharacteristicIndex, bool RequiresEncryption  >\n            static details::attribute_access_result characteristic_value_access( details::attribute_access_arguments& args, std::size_t )\n            {\n                const auto security_result = details::encryption_requirements< RequiresEncryption >::check( args.connection_security );\n\n                if ( security_result != details::attribute_access_result::success )\n                    return security_result;\n\n                if ( args.type != details::attribute_access_type::read )\n                    return details::attribute_access_result::write_not_permitted;\n\n                const char* value  = static_cast< const char* >( static_cast< const void* >( Text::value() ) );\n                std::size_t length = Text::size();\n\n                if ( args.buffer_offset > length )\n                    return details::attribute_access_result::invalid_offset;\n\n                args.buffer_size = std::min< std::size_t >( args.buffer_size, length - args.buffer_offset );\n\n                // copy data\n                std::copy( value + args.buffer_offset, value + args.buffer_offset + args.buffer_size, args.buffer );\n\n                return details::attribute_access_result::success;\n            }\n\n            static constexpr bool is_this( const void* )\n            {\n                return false;\n            }\n\n        };\n\n        struct meta_type :\n            details::characteristic_value_meta_type,\n            details::characteristic_value_declaration_parameter,\n            details::valid_characteristic_option_meta_type {};\n        /** @endcond */\n    };\n\n    /**\n     * @brief a constant string characteristic with the value Name\n     */\n    template < const char* const Name >\n    struct cstring_value : cstring_wrapper< cstring_value< Name > >\n    {\n        /** @cond HIDDEN_SYMBOLS */\n        static constexpr char const * name = Name;\n\n        static constexpr char const * value()\n        {\n            return name;\n        }\n\n        static constexpr std::size_t size()\n        {\n            return std::strlen( name );\n        }\n        /** @endcond */\n    };\n\n    /**\n     * @brief A fixed length and fixed value, read-only characteristic value\n     *\n     * @sa cstring_wrapper\n     * @sa cstring_value\n     */\n    template < const std::uint8_t* const Value, std::size_t Size >\n    struct fixed_blob_value : cstring_wrapper< fixed_blob_value< Value, Size > >\n    {\n        /** @cond HIDDEN_SYMBOLS */\n        static constexpr std::uint8_t const * value()\n        {\n            return Value;\n        }\n\n        static constexpr std::size_t size()\n        {\n            return Size;\n        }\n        /** @endcond */\n    };\n\n    namespace details {\n        template < class T >\n        struct invoke_read_handler {\n            template < class Server >\n            static constexpr std::uint8_t call_read_handler( std::size_t offset, std::size_t read_size, std::uint8_t* out_buffer, std::size_t& out_size, void* server )\n            {\n                return T::template call_read_handler< Server >( offset, read_size, out_buffer, out_size, server );\n            }\n        };\n\n        template <>\n        struct invoke_read_handler< no_such_type > {\n            template < class Server >\n            static constexpr std::uint8_t call_read_handler( std::size_t, std::size_t, std::uint8_t*, std::size_t&, void* )\n            {\n                return error_codes::read_not_permitted;\n            }\n        };\n\n        template < class T >\n        struct invoke_write_handler {\n            template < class Server, std::size_t ClientCharacteristicIndex >\n            static constexpr std::uint8_t call_write_handler( std::size_t offset, std::size_t write_size, const std::uint8_t* value, const details::client_characteristic_configuration& config, void* server )\n            {\n                return T::template call_write_handler< Server, ClientCharacteristicIndex >( offset, write_size, value, config, server );\n            }\n        };\n\n        template <>\n        struct invoke_write_handler< no_such_type > {\n            template < class Server, std::size_t ClientCharacteristicIndex >\n            static constexpr std::uint8_t call_write_handler( std::size_t, std::size_t, const std::uint8_t*, const details::client_characteristic_configuration&, void* )\n            {\n                return error_codes::write_not_permitted;\n            }\n        };\n\n        struct value_handler_base {\n\n            template < typename ... Options >\n            class value_impl : public details::value_impl_base< Options... >\n            {\n            public:\n                using read_handler_type = typename find_by_meta_type< characteristic_value_read_handler_meta_type, Options... >::type;\n                using write_handler_type = typename find_by_meta_type< characteristic_value_write_handler_meta_type, Options... >::type;\n                static constexpr bool no_read          = has_option< no_read_access, Options... >::value;\n                static constexpr bool no_write         = has_option< no_write_access, Options... >::value;\n\n                static constexpr bool has_read_handler = !std::is_same< read_handler_type, no_such_type >::value;\n                static constexpr bool has_read_access  = has_read_handler && !no_read;\n                static constexpr bool has_write_access = !std::is_same< write_handler_type, no_such_type >::value;\n                static constexpr bool has_write_without_response = details::has_option< write_without_response, Options... >::value;\n                static constexpr bool has_notification = has_option< notify, Options... >::value;\n                static constexpr bool has_indication   = has_option< indicate, Options... >::value;\n\n                static_assert( !( no_write && ( has_write_access || has_write_without_response ) ), \"There is no point in providing a write_handler and disabling write by using no_write_access\" );\n\n                static_assert( !has_notification || ( has_notification && has_read_handler ), \"When enabling notification, the characteristic needs to have a read_handler\" );\n                static_assert( !has_indication || ( has_indication && has_read_handler ), \"When enabling indications, the characteristic needs to have a read_handler\" );\n\n                static_assert( has_read_access || has_write_access || has_notification || has_indication, \"Ups!\");\n\n                template < class Server, std::size_t ClientCharacteristicIndex, bool RequiresEncryption >\n                static attribute_access_result characteristic_value_access( attribute_access_arguments& args, std::size_t /* attribute_index */ )\n                {\n                    const auto security_result = details::encryption_requirements< RequiresEncryption >::check( args.connection_security );\n\n                    if ( security_result != details::attribute_access_result::success )\n                        return security_result;\n\n                    if ( args.type == attribute_access_type::read )\n                    {\n                        return static_cast< attribute_access_result >(\n                            invoke_read_handler< read_handler_type >::template call_read_handler< Server >( args.buffer_offset, args.buffer_size, args.buffer, args.buffer_size, args.server ) );\n                    }\n                    else if ( args.type == attribute_access_type::write )\n                    {\n                        return static_cast< attribute_access_result >(\n                            invoke_write_handler< write_handler_type >::template call_write_handler< Server, ClientCharacteristicIndex >( args.buffer_offset, args.buffer_size, args.buffer, args.client_config, args.server ) );\n                    }\n                    else\n                    {\n                        return attribute_access_result::request_not_supported;\n                    }\n                }\n\n                static constexpr bool is_this( const void* /* value */ )\n                {\n                    return false;\n                }\n            };\n\n            struct meta_type :\n                characteristic_value_meta_type,\n                characteristic_value_declaration_parameter,\n                details::valid_characteristic_option_meta_type {};\n        };\n\n        template < typename T >\n        inline std::pair< std::uint8_t, T > deserialize( std::size_t write_size, const std::uint8_t* value )\n        {\n            static_assert( CHAR_BIT == 8, \"needs porting!\" );\n\n            if ( write_size != sizeof( T ) )\n                return std::pair< std::uint8_t, T >{ error_codes::invalid_attribute_value_length, 0 };\n\n            T result = 0;\n\n            for ( const std::uint8_t* v = value + sizeof( T ); v != value; --v )\n            {\n                result = ( result << 8 ) | *( v - 1 );\n            }\n\n            return std::pair< std::uint8_t, T >{ error_codes::success, result };\n        }\n\n        template <>\n        inline std::pair< std::uint8_t, bool > deserialize( std::size_t write_size, const std::uint8_t* value )\n        {\n            if ( write_size != 1 )\n                return std::make_pair( error_codes::invalid_attribute_value_length, false );\n\n            if ( *value == 0 )\n            {\n                return std::pair< std::uint8_t, bool >{ error_codes::success, false };\n            }\n            else if ( *value == 1 )\n            {\n                return std::pair< std::uint8_t, bool >{ error_codes::success, true };\n            }\n\n            return std::pair< std::uint8_t, bool >{ error_codes::out_of_range, false };\n        }\n    }\n\n    /**\n     * @brief binds a free function as a read handler for the given characteristic\n     *\n     * The handler can be used to handle blobs. The handler can be used with a\n     * bluetoe::no_read_access parameter in conjunction with bluetoe::indicate or bluetoe::notify to provide the\n     * data to a notification or indication without the charactertic beeing able to be read.\n     * If only a read handler is passed to the bluetoe::characteristic, the characteristic will be read only.\n     * If the characteristic value will always be smaller than 21 octets, using a bluetoe::free_read_handler will save\n     * you from coping with an offset.\n     *\n     * @tparam F pointer to function to handle a read request\n     * @param offset offset in octets into the characteristic beeing read. If the offset is larger than the characteristic,\n     *        the handler should return bluetoe::error_codes::invalid_offset\n     * @param read_size the maximum size, a client is able to read from the characteristic. This is the maximum, that can be\n     *                  copied to the out_buffer, without overflowing it. Reading just a part of the characteristic (because\n     *                  of the limited out_buffer size) is fine and not an error.\n     * @param out_buffer Output buffer to copy the data, that is read.\n     * @param out_size The actual number of octets copied to out_buffer. out_size must be smaller or equal to read_size.\n     *\n     * @retval If the characteristic value could be read successfully (even when the out_buffer was to small, to read the whole value),\n     *         the function should return luetoe::error_codes::success. In all other cases, Bluetoe will generate an error response to\n     *         a read request and directly use the return value as error code. For usefull error codes, have a look at\n     *         bluetoe::error_codes::error_codes.\n     *\n     * @sa characteristic\n     * @sa free_read_handler\n     * @sa free_write_blob_handler\n     * @sa free_raw_write_handler\n     * @sa bluetoe::error_codes::error_codes\n     */\n    template < std::uint8_t (*F)( std::size_t offset, std::size_t read_size, std::uint8_t* out_buffer, std::size_t& out_size ) >\n    struct free_read_blob_handler : details::value_handler_base\n    {\n        /** @cond HIDDEN_SYMBOLS */\n        template < class Server >\n        static constexpr std::uint8_t call_read_handler( std::size_t offset, std::size_t read_size, std::uint8_t* out_buffer, std::size_t& out_size, void* )\n        {\n            return F( offset, read_size, out_buffer, out_size );\n        }\n\n        struct meta_type : details::value_handler_base::meta_type, details::characteristic_value_read_handler_meta_type {};\n        /** @endcond */\n    };\n\n    /**\n     * @brief binds a free function as a read handler for the given characteristic\n     *\n     * This handler is functional similar to free_read_blob_handler, but can not be used for handling requests to\n     * large characteristics. To be on the safe side, this type of handler should not be used for characteristic values\n     * larger than 20 octets.\n     * The handler can be used with a\n     * bluetoe::no_read_access parameter in conjunction with bluetoe::indicate or bluetoe::notify to provide the\n     * data to a notification or indication without the charactertic beeing able to be read.\n     * If only a read handler is passed to the bluetoe::characteristic, the characteristic will be read only.\n     *\n     * @tparam F pointer to function to handle a read request\n     * @param read_size the maximum size, a client is able to read from the characteristic. This is the maximum, that can be\n     *                  copied to the out_buffer, without overflowing it. Reading just a part of the characteristic (because\n     *                  of the limited out_buffer size) is fine and not an error.\n     * @param out_buffer Output buffer to copy the data, that is read.\n     * @param out_size The actual number of octets copied to out_buffer. out_size must be smaller or equal to read_size.\n     *\n     * @retval If the characteristic value could be read successfully (even when the out_buffer was to small, to read the whole value),\n     *         the function should return luetoe::error_codes::success. In all other cases, Bluetoe will generate an error response to\n     *         a read request and directly use the return value as error code. For usefull error codes, have a look at\n     *         bluetoe::error_codes::error_codes.\n     *\n     * @sa characteristic\n     * @sa free_read_blob_handler\n     * @sa free_write_blob_handler\n     * @sa free_raw_write_handler\n     * @sa bluetoe::error_codes::error_codes\n     */\n    template < std::uint8_t (*F)( std::size_t read_size, std::uint8_t* out_buffer, std::size_t& out_size ) >\n    struct free_read_handler : details::value_handler_base\n    {\n        /** @cond HIDDEN_SYMBOLS */\n        template < class Server >\n        static constexpr std::uint8_t call_read_handler( std::size_t offset, std::size_t read_size, std::uint8_t* out_buffer, std::size_t& out_size, void* )\n        {\n            return offset == 0\n                ? F( read_size, out_buffer, out_size )\n                : static_cast< std::uint8_t >( error_codes::attribute_not_long );\n        }\n\n        struct meta_type : details::value_handler_base::meta_type, details::characteristic_value_read_handler_meta_type {};\n        /** @endcond */\n    };\n\n    /**\n     * @brief binds a free function as a write handler for the given characteristic\n     *\n     * The handler can be used to handle blobs.\n     * If only a write handler is passed to the bluetoe::characteristic, the characteristic will be write only.\n     * If the characteristic value will always be smaller than 21 octets, using a bluetoe::free_raw_write_handler will save\n     * you from coping with an offset.\n     *\n     * @tparam F pointer to function to handle a write request\n     *\n     * @param offset offset in octets into the characteristic beeing written. If the offset is larger than the characteristic,\n     *        the handler should return bluetoe::error_codes::invalid_offset\n     * @param write_size The size of the data that should be written to the characteristic value. If the size given is to\n     *            large, the handler should return bluetoe::error_codes::invalid_attribute_value_length.\n     * @param value Input buffer containing the desired characteristic value.\n     *\n     * @retval If the characteristic value could be read successfully (even when the out_buffer was to small, to read the whole value),\n     *         the function should return luetoe::error_codes::success. In all other cases, Bluetoe will generate an error response to\n     *         a read request and directly use the return value as error code. For usefull error codes, have a look at\n     *         bluetoe::error_codes::error_codes.\n     *\n     * @sa characteristic\n     * @sa free_read_blob_handler\n     * @sa free_read_handler\n     * @sa free_raw_write_handler\n     * @sa bluetoe::error_codes::error_codes\n     */\n    template < std::uint8_t (*F)( std::size_t offset, std::size_t write_size, const std::uint8_t* value ) >\n    struct free_write_blob_handler : details::value_handler_base\n    {\n        /** @cond HIDDEN_SYMBOLS */\n        template < class Server, std::size_t ClientCharacteristicIndex >\n        static constexpr std::uint8_t call_write_handler( std::size_t offset, std::size_t write_size, const std::uint8_t* value, const details::client_characteristic_configuration& , void* )\n        {\n            return F( offset, write_size, value );\n        }\n\n        struct meta_type : details::value_handler_base::meta_type, details::characteristic_value_write_handler_meta_type {};\n        /** @endcond */\n    };\n\n    /**\n     * @brief binds a free function as a write handler for the given characteristic\n     *\n     * If only a write handler is passed to the bluetoe::characteristic, the characteristic will be write only.\n     * To handle characteristic value sizes larger than 20 octets, a free_write_blob_handler should be used.\n     *\n     * @tparam F pointer to function to handle a write request\n     *\n     * @param write_size The size of the data that should be written to the characteristic value. If the size given is to\n     *            large, the handler should return bluetoe::error_codes::invalid_attribute_value_length.\n     * @param value Input buffer containing the desired characteristic value.\n     *\n     * @retval If the characteristic value could be read successfully (even when the out_buffer was to small, to read the whole value),\n     *         the function should return luetoe::error_codes::success. In all other cases, Bluetoe will generate an error response to\n     *         a read request and directly use the return value as error code. For usefull error codes, have a look at\n     *         bluetoe::error_codes::error_codes.\n     *\n     * @sa characteristic\n     * @sa free_read_blob_handler\n     * @sa free_read_handler\n     * @sa free_write_blob_handler\n     * @sa bluetoe::error_codes::error_codes\n     */\n    template < std::uint8_t (*F)( std::size_t write_size, const std::uint8_t* value ) >\n    struct free_raw_write_handler : details::value_handler_base\n    {\n        /** @cond HIDDEN_SYMBOLS */\n        template < class Server, std::size_t ClientCharacteristicIndex >\n        static constexpr std::uint8_t call_write_handler( std::size_t offset, std::size_t write_size, const std::uint8_t* value, const details::client_characteristic_configuration& , void* )\n        {\n            return offset == 0\n                ? F( write_size, value )\n                : static_cast< std::uint8_t >( error_codes::attribute_not_long );\n        }\n\n        struct meta_type : details::value_handler_base::meta_type, details::characteristic_value_write_handler_meta_type {};\n        /** @endcond */\n    };\n\n    template < class Obj, Obj& O, std::uint8_t (Obj::*F)( std::size_t offset, std::size_t read_size, std::uint8_t* out_buffer, std::size_t& out_size ) >\n    struct read_blob_handler : details::value_handler_base\n    {\n        /** @cond HIDDEN_SYMBOLS */\n        template < class Server >\n        static constexpr std::uint8_t call_read_handler( std::size_t offset, std::size_t read_size, std::uint8_t* out_buffer, std::size_t& out_size, void* )\n        {\n            return (O.*F)( offset, read_size, out_buffer, out_size );\n        }\n\n        struct meta_type : details::value_handler_base::meta_type, details::characteristic_value_read_handler_meta_type {};\n        /** @endcond */\n    };\n\n    template < class Obj, const Obj& O, std::uint8_t (Obj::*F)( std::size_t offset, std::size_t read_size, std::uint8_t* out_buffer, std::size_t& out_size ) const >\n    struct read_blob_handler_c : details::value_handler_base\n    {\n        /** @cond HIDDEN_SYMBOLS */\n        template < class Server >\n        static constexpr std::uint8_t call_read_handler( std::size_t offset, std::size_t read_size, std::uint8_t* out_buffer, std::size_t& out_size, void* )\n        {\n            return (O.*F)( offset, read_size, out_buffer, out_size );\n        }\n\n        struct meta_type : details::value_handler_base::meta_type, details::characteristic_value_read_handler_meta_type {};\n        /** @endcond */\n    };\n\n    template < class Obj, volatile Obj& O, std::uint8_t (Obj::*F)( std::size_t offset, std::size_t read_size, std::uint8_t* out_buffer, std::size_t& out_size ) volatile >\n    struct read_blob_handler_v : details::value_handler_base\n    {\n        /** @cond HIDDEN_SYMBOLS */\n        template < class Server >\n        static constexpr std::uint8_t call_read_handler( std::size_t offset, std::size_t read_size, std::uint8_t* out_buffer, std::size_t& out_size, void* )\n        {\n            return (O.*F)( offset, read_size, out_buffer, out_size );\n        }\n\n        struct meta_type : details::value_handler_base::meta_type, details::characteristic_value_read_handler_meta_type {};\n        /** @endcond */\n    };\n\n    template < class Obj, const volatile Obj& O, std::uint8_t (Obj::*F)( std::size_t offset, std::size_t read_size, std::uint8_t* out_buffer, std::size_t& out_size ) const volatile >\n    struct read_blob_handler_cv : details::value_handler_base\n    {\n        /** @cond HIDDEN_SYMBOLS */\n        template < class Server >\n        static constexpr std::uint8_t call_read_handler( std::size_t offset, std::size_t read_size, std::uint8_t* out_buffer, std::size_t& out_size, void* )\n        {\n            return (O.*F)( offset, read_size, out_buffer, out_size );\n        }\n\n        struct meta_type : details::value_handler_base::meta_type, details::characteristic_value_read_handler_meta_type {};\n        /** @endcond */\n    };\n\n    template < class Obj, Obj& O, std::uint8_t (Obj::*F)( std::size_t read_size, std::uint8_t* out_buffer, std::size_t& out_size ) >\n    struct read_handler : details::value_handler_base\n    {\n        /** @cond HIDDEN_SYMBOLS */\n        template < class Server >\n        static constexpr std::uint8_t call_read_handler( std::size_t offset, std::size_t read_size, std::uint8_t* out_buffer, std::size_t& out_size, void* )\n        {\n            return offset == 0\n                ? (O.*F)( read_size, out_buffer, out_size )\n                : static_cast< std::uint8_t >( error_codes::attribute_not_long );\n        }\n\n        struct meta_type : details::value_handler_base::meta_type, details::characteristic_value_read_handler_meta_type {};\n        /** @endcond */\n    };\n\n    template < class Obj, const Obj& O, std::uint8_t (Obj::*F)( std::size_t read_size, std::uint8_t* out_buffer, std::size_t& out_size ) const >\n    struct read_handler_c : details::value_handler_base\n    {\n        /** @cond HIDDEN_SYMBOLS */\n        template < class Server >\n        static constexpr std::uint8_t call_read_handler( std::size_t offset, std::size_t read_size, std::uint8_t* out_buffer, std::size_t& out_size, void* )\n        {\n            return offset == 0\n                ? (O.*F)( read_size, out_buffer, out_size )\n                : static_cast< std::uint8_t >( error_codes::attribute_not_long );\n        }\n\n        struct meta_type : details::value_handler_base::meta_type, details::characteristic_value_read_handler_meta_type {};\n        /** @endcond */\n    };\n\n    template < class Obj, volatile Obj& O, std::uint8_t (Obj::*F)( std::size_t read_size, std::uint8_t* out_buffer, std::size_t& out_size ) volatile >\n    struct read_handler_v : details::value_handler_base\n    {\n        /** @cond HIDDEN_SYMBOLS */\n        template < class Server >\n        static constexpr std::uint8_t call_read_handler( std::size_t offset, std::size_t read_size, std::uint8_t* out_buffer, std::size_t& out_size, void* )\n        {\n            return offset == 0\n                ? (O.*F)( read_size, out_buffer, out_size )\n                : static_cast< std::uint8_t >( error_codes::attribute_not_long );\n        }\n\n        struct meta_type : details::value_handler_base::meta_type, details::characteristic_value_read_handler_meta_type {};\n        /** @endcond */\n    };\n\n    template < class Obj, const volatile Obj& O, std::uint8_t (Obj::*F)( std::size_t read_size, std::uint8_t* out_buffer, std::size_t& out_size ) const volatile >\n    struct read_handler_cv : details::value_handler_base\n    {\n        /** @cond HIDDEN_SYMBOLS */\n        template < class Server >\n        static constexpr std::uint8_t call_read_handler( std::size_t offset, std::size_t read_size, std::uint8_t* out_buffer, std::size_t& out_size, void* )\n        {\n            return offset == 0\n                ? (O.*F)( read_size, out_buffer, out_size )\n                : static_cast< std::uint8_t >( error_codes::attribute_not_long );\n        }\n\n        struct meta_type : details::value_handler_base::meta_type, details::characteristic_value_read_handler_meta_type {};\n        /** @endcond */\n    };\n\n    template < class Obj, Obj& O, std::uint8_t (Obj::*F)( std::size_t offset, std::size_t write_size, const std::uint8_t* value ) >\n    struct write_blob_handler : details::value_handler_base\n    {\n        /** @cond HIDDEN_SYMBOLS */\n        template < class Server, std::size_t ClientCharacteristicIndex >\n        static constexpr std::uint8_t call_write_handler( std::size_t offset, std::size_t write_size, const std::uint8_t* value, const details::client_characteristic_configuration& , void* )\n        {\n            return (O.*F)( offset, write_size, value );\n        }\n\n        struct meta_type : details::value_handler_base::meta_type, details::characteristic_value_write_handler_meta_type {};\n        /** @endcond */\n    };\n\n    template < class Obj, const Obj& O, std::uint8_t (Obj::*F)( std::size_t offset, std::size_t write_size, const std::uint8_t* value ) const >\n    struct write_blob_handler_c : details::value_handler_base\n    {\n        /** @cond HIDDEN_SYMBOLS */\n        template < class Server, std::size_t ClientCharacteristicIndex >\n        static constexpr std::uint8_t call_write_handler( std::size_t offset, std::size_t write_size, const std::uint8_t* value, const details::client_characteristic_configuration& , void* )\n        {\n            return (O.*F)( offset, write_size, value );\n        }\n\n        struct meta_type : details::value_handler_base::meta_type, details::characteristic_value_write_handler_meta_type {};\n        /** @endcond */\n    };\n\n    template < class Obj, volatile Obj& O, std::uint8_t (Obj::*F)( std::size_t offset, std::size_t write_size, const std::uint8_t* value ) volatile >\n    struct write_blob_handler_v : details::value_handler_base\n    {\n        /** @cond HIDDEN_SYMBOLS */\n        template < class Server, std::size_t ClientCharacteristicIndex >\n        static constexpr std::uint8_t call_write_handler( std::size_t offset, std::size_t write_size, const std::uint8_t* value, const details::client_characteristic_configuration& , void* )\n        {\n            return (O.*F)( offset, write_size, value );\n        }\n\n        struct meta_type : details::value_handler_base::meta_type, details::characteristic_value_write_handler_meta_type {};\n        /** @endcond */\n    };\n\n    template < class Obj, const volatile Obj& O, std::uint8_t (Obj::*F)( std::size_t offset, std::size_t write_size, const std::uint8_t* value ) const volatile >\n    struct write_blob_handler_cv : details::value_handler_base\n    {\n        /** @cond HIDDEN_SYMBOLS */\n        template < class Server, std::size_t ClientCharacteristicIndex >\n        static constexpr std::uint8_t call_write_handler( std::size_t offset, std::size_t write_size, const std::uint8_t* value, const details::client_characteristic_configuration& , void* )\n        {\n            return (O.*F)( offset, write_size, value );\n        }\n\n        struct meta_type : details::value_handler_base::meta_type, details::characteristic_value_write_handler_meta_type {};\n        /** @endcond */\n    };\n\n    template < class Obj, Obj& O, std::uint8_t (Obj::*F)( std::size_t write_size, const std::uint8_t* value ) >\n    struct write_handler : details::value_handler_base\n    {\n        /** @cond HIDDEN_SYMBOLS */\n        template < class Server, std::size_t ClientCharacteristicIndex >\n        static constexpr std::uint8_t call_write_handler( std::size_t offset, std::size_t write_size, const std::uint8_t* value, const details::client_characteristic_configuration& , void* )\n        {\n            return offset == 0\n                ? (O.*F)( write_size, value )\n                : static_cast< std::uint8_t >( error_codes::attribute_not_long );\n        }\n\n        struct meta_type : details::value_handler_base::meta_type, details::characteristic_value_write_handler_meta_type {};\n        /** @endcond */\n    };\n\n    template < class Obj, const Obj& O, std::uint8_t (Obj::*F)( std::size_t write_size, const std::uint8_t* value ) const >\n    struct write_handler_c : details::value_handler_base\n    {\n        /** @cond HIDDEN_SYMBOLS */\n        template < class Server, std::size_t ClientCharacteristicIndex >\n        static constexpr std::uint8_t call_write_handler( std::size_t offset, std::size_t write_size, const std::uint8_t* value, const details::client_characteristic_configuration& , void* )\n        {\n            return offset == 0\n                ? (O.*F)( write_size, value )\n                : static_cast< std::uint8_t >( error_codes::attribute_not_long );\n        }\n\n        struct meta_type : details::value_handler_base::meta_type, details::characteristic_value_write_handler_meta_type {};\n        /** @endcond */\n    };\n\n    template < class Obj, volatile Obj& O, std::uint8_t (Obj::*F)( std::size_t write_size, const std::uint8_t* value ) volatile >\n    struct write_handler_v : details::value_handler_base\n    {\n        /** @cond HIDDEN_SYMBOLS */\n        template < class Server, std::size_t ClientCharacteristicIndex >\n        static std::uint8_t call_write_handler( std::size_t offset, std::size_t write_size, const std::uint8_t* value, const details::client_characteristic_configuration& , void* )\n        {\n            return offset == 0\n                ? (O.*F)( write_size, value )\n                : static_cast< std::uint8_t >( error_codes::attribute_not_long );\n        }\n\n        struct meta_type : details::value_handler_base::meta_type, details::characteristic_value_write_handler_meta_type {};\n        /** @endcond */\n    };\n\n    template < class Obj, const volatile Obj& O, std::uint8_t (Obj::*F)( std::size_t write_size, const std::uint8_t* value ) const volatile >\n    struct write_handler_cv : details::value_handler_base\n    {\n        /** @cond HIDDEN_SYMBOLS */\n        template < class Server, std::size_t ClientCharacteristicIndex >\n        static constexpr std::uint8_t call_write_handler( std::size_t offset, std::size_t write_size, const std::uint8_t* value, const details::client_characteristic_configuration& , void* )\n        {\n            return offset == 0\n                ? (O.*F)( write_size, value )\n                : static_cast< std::uint8_t >( error_codes::attribute_not_long );\n        }\n\n        struct meta_type : details::value_handler_base::meta_type, details::characteristic_value_write_handler_meta_type {};\n        /** @endcond */\n    };\n\n    template < class Mixin, std::uint8_t (Mixin::*F)( std::size_t read_size, std::uint8_t* out_buffer, std::size_t& out_size ) >\n    struct mixin_read_handler : details::value_handler_base\n    {\n        /** @cond HIDDEN_SYMBOLS */\n        template < class Server >\n        static std::uint8_t call_read_handler( std::size_t offset, std::size_t read_size, std::uint8_t* out_buffer, std::size_t& out_size, void* server )\n        {\n            assert( server );\n            static_assert( std::is_convertible< Server*, Mixin* >::value, \"Use bluetoe::mixin<> to mixin an instance of the mixin_read_handler into the server.\" );\n\n            Mixin& mixin = static_cast< Mixin& >( *static_cast< Server* >( server ) );\n\n            return offset == 0\n                ? (mixin.*F)( read_size, out_buffer, out_size )\n                : static_cast< std::uint8_t >( error_codes::attribute_not_long );\n\n        }\n\n        struct meta_type : details::value_handler_base::meta_type, details::characteristic_value_read_handler_meta_type {};\n        /** @endcond */\n    };\n\n    template < class Mixin, std::uint8_t (Mixin::*F)( std::size_t write_size, const std::uint8_t* value ) >\n    struct mixin_write_handler : details::value_handler_base\n    {\n        /** @cond HIDDEN_SYMBOLS */\n        template < class Server, std::size_t ClientCharacteristicIndex >\n        static std::uint8_t call_write_handler( std::size_t offset, std::size_t write_size, const std::uint8_t* value, const details::client_characteristic_configuration& , void* server )\n        {\n            assert( server );\n            static_assert( std::is_convertible< Server*, Mixin* >::value, \"Use bluetoe::mixin<> to mixin an instance of the mixin_write_handler into the server.\" );\n\n            Mixin& mixin = static_cast< Mixin& >( *static_cast< Server* >( server ) );\n\n            return offset == 0\n                ? (mixin.*F)( write_size, value )\n                : static_cast< std::uint8_t >( error_codes::attribute_not_long );\n        }\n\n        struct meta_type : details::value_handler_base::meta_type, details::characteristic_value_write_handler_meta_type {};\n        /** @endcond */\n    };\n\n    template < class Mixin, std::uint8_t (Mixin::*F)( std::size_t offset, std::size_t read_size, std::uint8_t* out_buffer, std::size_t& out_size ) >\n    struct mixin_read_blob_handler : details::value_handler_base\n    {\n        /** @cond HIDDEN_SYMBOLS */\n        template < class Server >\n        static std::uint8_t call_read_handler( std::size_t offset, std::size_t read_size, std::uint8_t* out_buffer, std::size_t& out_size, void* server )\n        {\n            assert( server );\n            static_assert( std::is_convertible< Server*, Mixin* >::value, \"Use bluetoe::mixin<> to mixin an instance of the mixin_read_blob_handler into the server.\" );\n\n            Mixin& mixin = static_cast< Mixin& >( *static_cast< Server* >( server ) );\n            return (mixin.*F)( offset, read_size, out_buffer, out_size );\n        }\n\n        struct meta_type : details::value_handler_base::meta_type, details::characteristic_value_read_handler_meta_type {};\n        /** @endcond */\n    };\n\n    template < class Mixin, std::uint8_t (Mixin::*F)( std::size_t offset, std::size_t write_size, const std::uint8_t* value ) >\n    struct mixin_write_blob_handler : details::value_handler_base\n    {\n        /** @cond HIDDEN_SYMBOLS */\n        template < class Server, std::size_t ClientCharacteristicIndex >\n        static std::uint8_t call_write_handler( std::size_t offset, std::size_t write_size, const std::uint8_t* value, const details::client_characteristic_configuration& , void* server )\n        {\n            assert( server );\n            static_assert( std::is_convertible< Server*, Mixin* >::value, \"Use bluetoe::mixin<> to mixin an instance of the mixin_write_blob_handler into the server.\" );\n\n            Mixin& mixin = static_cast< Mixin& >( *static_cast< Server* >( server ) );\n            return (mixin.*F)( offset, write_size, value );\n        }\n\n        struct meta_type : details::value_handler_base::meta_type, details::characteristic_value_write_handler_meta_type {};\n        /** @endcond */\n    };\n\n    /**\n     * @brief characteristic value binding for a control point\n     *\n     * This is intendet for control points that respond by an indication. If the bound handler returns { error_codes::success, true },\n     * an indication will be marked to be pending for this characteristic and as soon as there is a free slot in the ling layer,\n     * the read handler for this characteristic will be called to retrieve the intended value for the indication.\n     *\n     * @sa mixin_write_notification_control_point_handler\n     */\n    template < class Mixin, std::pair< std::uint8_t, bool > (Mixin::*F)( std::size_t write_size, const std::uint8_t* value ), typename IndicationUUID >\n    struct mixin_write_indication_control_point_handler : details::value_handler_base\n    {\n        /** @cond HIDDEN_SYMBOLS */\n        template < class Server, std::size_t >\n        static std::uint8_t call_write_handler( std::size_t offset, std::size_t write_size, const std::uint8_t* value, const details::client_characteristic_configuration& config, void* server_ptr )\n        {\n            assert( server_ptr );\n            static_assert( std::is_convertible< Server*, Mixin* >::value, \"Use bluetoe::mixin<> to mixin an instance of the mixin_write_handler into the server.\" );\n\n            if ( offset != 0 )\n                return static_cast< std::uint8_t >( error_codes::attribute_not_long );\n\n            // we have a void pointer, the type of the server and the server is derived from the mixin\n            Server& server = *static_cast< Server* >( server_ptr );\n            Mixin&  mixin  = static_cast< Mixin& >( server );\n\n            // as this is a indication control point, this thingy must be configured for indications\n            if ( !server.template configured_for_indications< IndicationUUID >( config ) )\n                return error_codes::cccd_improperly_configured;\n\n            const std::pair< std::uint8_t, bool > result = (mixin.*F)( write_size, value );\n\n            if ( result.second )\n                server.template indicate< IndicationUUID >();\n\n            return static_cast< std::uint8_t >( result.first );\n        }\n\n        struct meta_type : details::value_handler_base::meta_type, details::characteristic_value_write_handler_meta_type {};\n        /** @endcond */\n    };\n\n    /**\n     * @brief characteristic value binding for a control point\n     *\n     * Similar to mixin_write_indication_control_point_handler but sends a notification in response.\n     * @sa mixin_write_indication_control_point_handler\n     */\n    template < class Mixin, std::pair< std::uint8_t, bool > (Mixin::*F)( std::size_t write_size, const std::uint8_t* value ), typename NotificationUUID >\n    struct mixin_write_notification_control_point_handler : details::value_handler_base\n    {\n        /** @cond HIDDEN_SYMBOLS */\n        template < class Server, std::size_t  >\n        static std::uint8_t call_write_handler( std::size_t offset, std::size_t write_size, const std::uint8_t* value, const details::client_characteristic_configuration& config, void* server_ptr )\n        {\n            assert( server_ptr );\n            static_assert( std::is_convertible< Server*, Mixin* >::value, \"Use bluetoe::mixin<> to mixin an instance of the mixin_write_handler into the server.\" );\n\n            if ( offset != 0 )\n                return static_cast< std::uint8_t >( error_codes::attribute_not_long );\n\n            // we have a void pointer, the type of the server and the server is derived from the mixin\n            Server& server = *static_cast< Server* >( server_ptr );\n            Mixin&  mixin  = static_cast< Mixin& >( server );\n\n            // as this is a notification control point, this thingy must be configured for notification\n            if ( !server.template configured_for_notifications< NotificationUUID >( config ) )\n                return error_codes::cccd_improperly_configured;\n\n            const std::pair< std::uint8_t, bool > result = (mixin.*F)( write_size, value );\n\n            if ( result.second )\n                server.template notify< NotificationUUID >();\n\n            return static_cast< std::uint8_t >( result.first );\n        }\n\n        struct meta_type : details::value_handler_base::meta_type, details::characteristic_value_write_handler_meta_type {};\n        /** @endcond */\n    };\n\n    /**\n     * @brief binds a free function as a write handler for the given characteristic\n     *\n     * This handler handle write to characteristics with a specific size. The size if derived from the first\n     * template paramter. A std::uint32_t for example would result in a characteristic with a size of 4\n     * octets.\n     * If only a write handler is passed to the bluetoe::characteristic, the characteristic will be write only.\n     *\n     * @tparam T type of characteristic. Possible values are bool, std::uint8_t, std::uint16_t, std::uint32_t, std::uint64_t and there\n     *          signed counterpart.\n     *\n     * @tparam F pointer to function to handle a write request.\n     *\n     * @retval If the characteristic value could be written successfully the function should return luetoe::error_codes::success.\n     *         For usefull error codes, have a look at bluetoe::error_codes::error_codes.\n     *\n     * @sa characteristic\n     * @sa free_read_blob_handler\n     * @sa free_read_handler\n     * @sa free_write_blob_handler\n     * @sa bluetoe::error_codes::error_codes\n     */\n    template < typename T, std::uint8_t (*F)( T ) >\n    struct free_write_handler : details::value_handler_base\n    {\n        /** @cond HIDDEN_SYMBOLS */\n        template < class Server, std::size_t ClientCharacteristicIndex >\n        static std::uint8_t call_write_handler( std::size_t offset, std::size_t write_size, const std::uint8_t* value, const details::client_characteristic_configuration& , void* )\n        {\n            if ( offset != 0 )\n                return static_cast< std::uint8_t >( error_codes::attribute_not_long );\n\n            const std::pair< std::uint8_t, T > deserialized_value = details::deserialize< T >( write_size, value );\n\n            if ( deserialized_value.first != error_codes::success )\n                return deserialized_value.first;\n\n            return (*F)( deserialized_value.second );\n        }\n\n        struct meta_type : details::value_handler_base::meta_type, details::characteristic_value_write_handler_meta_type {};\n        /** @endcond */\n    };\n\n    /**\n     * @example read_write_handler_example.cpp\n     * Example, showing all possible alternatives to bind functions as read or write handler to a bluetooth characteristic.\n     */\n\n}\n\n#endif\n"
  },
  {
    "path": "bluetoe/custom_advertising.hpp",
    "content": "#ifndef BLUETOE_CUSTOM_ADVERTISING_HPP\n#define BLUETOE_CUSTOM_ADVERTISING_HPP\n\n#include <bluetoe/meta_types.hpp>\n\n#include <cstddef>\n#include <cstdint>\n#include <algorithm>\n\nnamespace bluetoe {\n\n    /**\n     * @brief provides data to be advertised\n     */\n    template < std::size_t Size, const std::uint8_t (&Data)[ Size ] >\n    struct custom_advertising_data\n    {\n        /** @cond HIDDEN_SYMBOLS */\n        constexpr bool advertising_data_dirty() const\n        {\n            return false;\n        }\n\n        std::size_t advertising_data( std::uint8_t* begin, std::size_t buffer_size ) const\n        {\n            const std::size_t copy_size = std::min( Size, buffer_size );\n            std::copy( &Data[ 0 ], &Data[ copy_size ], begin );\n\n            return copy_size;\n        }\n\n        struct meta_type :\n            details::advertising_data_meta_type,\n            details::valid_server_option_meta_type {};\n        /** @endcond */\n    };\n\n    struct auto_advertising_data\n    {\n        /** @cond HIDDEN_SYMBOLS */\n        constexpr bool advertising_data_dirty() const\n        {\n            return false;\n        }\n\n        struct meta_type :\n            details::advertising_data_meta_type,\n            details::valid_server_option_meta_type {};\n        /** @endcond */\n    };\n\n    /**\n     * @brief provides data to be advertised at runtime\n     *\n     * Add the set_runtime_custom_advertising_data() function to the server.\n     * By default, the advertings data is of length 0.\n     */\n    struct runtime_custom_advertising_data\n    {\n        /**\n         * @brief set the advertising data to be used.\n         *\n         * The function copies to the data given by begin and buffer_size into an\n         * internal buffer.\n         */\n        void set_runtime_custom_advertising_data( const std::uint8_t* begin, std::size_t buffer_size )\n        {\n            advertising_data_size_ = std::min( std::size_t{ advertising_data_max_size }, buffer_size );\n            std::copy( &begin[ 0 ], &begin[ advertising_data_size_ ], &advertising_data_[ 0 ] );\n\n            dirty_ = true;\n        }\n\n        /** @cond HIDDEN_SYMBOLS */\n        runtime_custom_advertising_data()\n            : advertising_data_size_( 0 )\n            , dirty_( false )\n        {\n        }\n\n        bool advertising_data_dirty()\n        {\n            const bool result = dirty_;\n            dirty_ = false;\n\n            return result;\n        }\n\n        std::size_t advertising_data( std::uint8_t* begin, std::size_t buffer_size ) const\n        {\n            const std::size_t copy_size = std::min( advertising_data_size_, buffer_size );\n            std::copy( &advertising_data_[ 0 ], &advertising_data_[ copy_size ], begin );\n\n            return copy_size;\n        }\n\n        struct meta_type :\n            details::advertising_data_meta_type,\n            details::valid_server_option_meta_type {};\n\n    private:\n        static constexpr std::size_t advertising_data_max_size = 31;\n        std::uint8_t advertising_data_[ advertising_data_max_size ];\n        std::size_t  advertising_data_size_;\n        bool dirty_;\n        /** @endcond */\n    };\n\n    /**\n     * @brief provides data to be use in response to a scan request\n     *\n     * @sa runtime_custom_scan_response_data\n     * @sa auto_scan_response_data\n     */\n    template < std::size_t Size, const std::uint8_t (&Data)[ Size ] >\n    struct custom_scan_response_data\n    {\n        /** @cond HIDDEN_SYMBOLS */\n        constexpr bool scan_response_data_dirty() const\n        {\n            return false;\n        }\n\n        std::size_t scan_response_data( std::uint8_t* begin, std::size_t buffer_size ) const\n        {\n            const std::size_t copy_size = std::min( Size, buffer_size );\n            std::copy( &Data[ 0 ], &Data[ copy_size ], begin );\n\n            return copy_size;\n        }\n\n        struct meta_type :\n            details::scan_response_data_meta_type,\n            details::valid_server_option_meta_type {};\n        /** @endcond */\n    };\n\n    /**\n     * @brief options, that allows Bluetoe to create the scan response data\n     *\n     * This is the default and currently, the implementation provides an empty\n     * scan response.\n     *\n     * @sa runtime_custom_scan_response_data\n     * @sa custom_scan_response_data\n     */\n    struct auto_scan_response_data\n    {\n        /** @cond HIDDEN_SYMBOLS */\n        constexpr bool scan_response_data_dirty() const\n        {\n            return false;\n        }\n\n        struct meta_type :\n            details::scan_response_data_meta_type,\n            details::valid_server_option_meta_type {};\n        /** @endcond */\n    };\n\n    /**\n     * @brief option, that allows to define the scan response data at runtime\n     *\n     * @sa auto_scan_response_data\n     * @sa custom_scan_response_data\n     */\n    struct runtime_custom_scan_response_data\n    {\n        /**\n         * @brief set the scan response data to be used.\n         *\n         * The function copies to the data given by begin and buffer_size into an\n         * internal buffer.\n         */\n        void set_runtime_custom_scan_response_data( const std::uint8_t* begin, std::size_t buffer_size )\n        {\n            scan_response_data_size_ = std::min( std::size_t{ scan_response_data_max_size }, buffer_size );\n            std::copy( &begin[ 0 ], &begin[ scan_response_data_size_ ], &scan_response_data_[ 0 ] );\n\n            dirty_ = true;\n        }\n\n        /** @cond HIDDEN_SYMBOLS */\n        runtime_custom_scan_response_data()\n            : scan_response_data_size_( 0 )\n            , dirty_( false )\n        {\n        }\n\n        std::size_t scan_response_data( std::uint8_t* begin, std::size_t buffer_size ) const\n        {\n            const std::size_t copy_size = std::min( scan_response_data_size_, buffer_size );\n            std::copy( &scan_response_data_[ 0 ], &scan_response_data_[ copy_size ], begin );\n\n            return copy_size;\n        }\n\n        bool scan_response_data_dirty()\n        {\n            const bool result = dirty_;\n            dirty_ = false;\n\n            return result;\n        }\n\n        struct meta_type :\n            details::scan_response_data_meta_type,\n            details::valid_server_option_meta_type {};\n\n    private:\n        static constexpr std::size_t scan_response_data_max_size = 31;\n        std::uint8_t scan_response_data_[ scan_response_data_max_size ];\n        std::size_t  scan_response_data_size_;\n        bool dirty_;\n        /** @endcond */\n    };\n}\n#endif\n\n"
  },
  {
    "path": "bluetoe/descriptor.hpp",
    "content": "#ifndef BLUETOE_DESCRIPTOR_HPP\n#define BLUETOE_DESCRIPTOR_HPP\n\n#include <bluetoe/meta_types.hpp>\n#include <cstdint>\n#include <cstddef>\n\nnamespace bluetoe {\n\n    namespace details {\n        struct descriptor_parameter {};\n    }\n\n    /**\n     * @brief User defined descriptor\n     *\n     * A user defined, read only descriptor with a 16-bit UUID.\n     * @note Currently, it is only supported to have one such user defined descriptor in a characteristic.\n     */\n    template < std::uint16_t UUID, const std::uint8_t* const Value, std::size_t Size >\n    struct descriptor\n    {\n        /** @cond HIDDEN_SYMBOLS */\n        struct meta_type : details::descriptor_parameter, details::valid_characteristic_option_meta_type {};\n        /** @endcond */\n    };\n}\n\n#endif\n"
  },
  {
    "path": "bluetoe/encryption.hpp",
    "content": "#ifndef BLUETOE_ENCRYPTION_HPP\n#define BLUETOE_ENCRYPTION_HPP\n\n#include <bluetoe/meta_tools.hpp>\n#include <bluetoe/meta_types.hpp>\n\nnamespace bluetoe {\n\n    template < typename ... Options >\n    class server;\n\n    template < typename ... Options >\n    class service;\n\n    template < typename ... Options >\n    class characteristic;\n\n    namespace details {\n        struct requires_encryption_meta_type {};\n        struct no_encryption_required_meta_type {};\n        struct may_require_encryption_meta_type {};\n    }\n\n    /**\n     * @brief defines that access to characteristic(s) require an encrypted link without\n     *        MITM Protection.\n     *\n     * Can be used on server, service or characteristic level to define that the access\n     * to a characteristic value or CCCD, requires an encrypted link. If the link is not encrypted,\n     * when accessing the characteristic, Bluetoe replies with an ATT Insufficient Authorization\n     * error, if the requesting device is not paired and ATT Insufficient Encryption, if the\n     * device is paired, but the link is not encrypted.\n     * (see table 10.2 Vol 3, Part C, 10.3.1)\n     *\n     * If applied to a server or service definition, this definition applies to all containing\n     * characteristics, where it can be overridden.\n     *\n     * Example\n     * @code\n    char simple_value = 0;\n    constexpr char name[] = \"This is the name of the characteristic\";\n\n    using server = bluetoe::server<\n        // By default, require encryption for all characteristics of\n        // all services.\n        bluetoe::requires_encryption,\n        // Service A\n        bluetoe::service<\n            // But for this service, no encryption is required\n            bluetoe::no_encryption_required,\n            service_uuid_a,\n            ...\n        >,\n        // Service B\n        bluetoe::service<\n            service_uuid_b,\n            bluetoe::characteristic<\n                char_uuid,\n                // For all characteristics of this service, but this characteristic,\n                // encryption is required\n                bluetoe::no_encryption_required\n            >,\n            ...\n        >,\n        // Service C\n    >;\n     * @endcode\n     *\n     * @sa characteristic\n     * @sa service\n     * @sa server\n     * @sa no_encryption_required\n     * @sa may_require_encryption\n     */\n    struct requires_encryption {\n        /** @cond HIDDEN_SYMBOLS */\n        struct meta_type :\n            details::requires_encryption_meta_type,\n            details::valid_server_option_meta_type,\n            details::valid_service_option_meta_type,\n            details::valid_characteristic_option_meta_type {};\n        /** @endcond */\n    };\n\n    /**\n     * @brief defines that access to characteristic(s) does not require an encrypted link.\n     *\n     * If applied to a server or service definition, this definition applies to all containing\n     * characteristics, where it can be overridden.\n     *\n     * If no characteristic in the entire server requires encryption, Bluetoe will leave out\n     * the support code for encryption.\n     *\n     * @sa requires_encryption\n     * @sa may_require_encryption\n     */\n    struct no_encryption_required {\n        /** @cond HIDDEN_SYMBOLS */\n        struct meta_type :\n            details::no_encryption_required_meta_type,\n            details::valid_server_option_meta_type,\n            details::valid_service_option_meta_type,\n            details::valid_characteristic_option_meta_type {};\n        /** @endcond */\n    };\n\n    /**\n     * @brief defines that a characteristic may require encyption\n     *\n     * The declaration forces bluetoe to add the required code for supporting encrypted\n     * links. Basecally this means that a custom characterstic read or write handler\n     * may require encryption under specific circumstances.\n     *\n     * This option can be passed to a server, service or a characteristic declaration.\n     *\n     * @attention For characteristic value bindings that determine the ATT error code\n     *            on their own, this basecally mean, that the characteristic does _not_\n     *            require encryption!\n     *\n     * @sa requires_encryption\n     * @sa no_encryption_required\n     */\n    struct may_require_encryption {\n        /** @cond HIDDEN_SYMBOLS */\n        struct meta_type :\n            details::may_require_encryption_meta_type,\n            details::valid_server_option_meta_type,\n            details::valid_service_option_meta_type,\n            details::valid_characteristic_option_meta_type {};\n        /** @endcond */\n    };\n\n    namespace details {\n\n        template < typename Server, bool Default = false >\n        struct requires_encryption_support_t\n        {\n            static bool constexpr value = Default;\n        };\n\n        template < typename ... Options, typename T >\n        struct requires_encryption_support_t< std::tuple< T, Options... >, false >\n        {\n            static bool constexpr value =\n                requires_encryption_support_t< T, false >::value\n             || requires_encryption_support_t< std::tuple< Options... >, false >::value;\n        };\n\n        template < typename ... Options, typename T >\n        struct requires_encryption_support_t< std::tuple< T, Options... >, true >\n        {\n            static bool constexpr value =\n                requires_encryption_support_t< T, true >::value\n             && requires_encryption_support_t< std::tuple< Options... >, true >::value;\n        };\n\n        template < bool Default, typename ... Options >\n        struct encryption_default\n        {\n            static bool constexpr require_encryption =\n                details::has_option< requires_encryption, Options... >::value;\n\n            static bool constexpr may_require =\n                details::has_option< may_require_encryption, Options... >::value;\n\n            static bool constexpr require_not_encryption =\n                 details::has_option< no_encryption_required, Options... >::value;\n\n            // require !require default | value\n            //    true    false   false |  true\n            //   false     true   false | false\n            //   false    false   false | false\n            //    true    false    true |  true\n            //   false     true    true | false\n            //   false    false    true |  true\n            static bool constexpr value =\n                ( require_encryption && !require_not_encryption )\n             || ( !require_encryption && !require_not_encryption && Default );\n\n            static bool constexpr maybe = value || may_require;\n        };\n\n        template < typename ... Options, bool Default >\n        struct requires_encryption_support_t< bluetoe::server< Options... >, Default > {\n            static bool constexpr default_val = encryption_default< Default, Options... >::maybe;\n\n            static bool constexpr value =\n                requires_encryption_support_t<\n                    typename bluetoe::server< Options... >::services,\n                    default_val >::value;\n        };\n\n        template < typename ... Options, bool Default >\n        struct requires_encryption_support_t< bluetoe::service< Options... >, Default > {\n            static bool constexpr default_val = encryption_default< Default, Options... >::maybe;\n\n            static bool constexpr value =\n                requires_encryption_support_t<\n                    typename bluetoe::service< Options... >::characteristics,\n                    default_val >::value;\n        };\n\n        template < typename ... Options, bool Default >\n        struct requires_encryption_support_t< bluetoe::characteristic< Options... >, Default > {\n            // @TODO the default for a characteristic should always be true\n            static bool constexpr value = encryption_default< Default, Options... >::maybe;\n        };\n\n        template < typename Characteristic, typename Service, typename Server >\n        struct characteristic_requires_encryption;\n\n        template < typename ... CharacteristicOptions, typename ... ServiceOptions, typename ... ServerOptions >\n        struct characteristic_requires_encryption<\n            bluetoe::characteristic< CharacteristicOptions... >,\n            bluetoe::service< ServiceOptions... >,\n            bluetoe::server< ServerOptions... > >\n        {\n            // @TODO the default for a characteristic should always be true\n            static bool constexpr server_requires_encryption  = encryption_default< false, ServerOptions... >::value;\n            static bool constexpr service_requires_encryption = encryption_default< server_requires_encryption, ServiceOptions... >::value;\n\n            static bool constexpr value                       = encryption_default< service_requires_encryption, CharacteristicOptions... >::value;\n        };\n    }\n\n} // namespace bluetoe\n\n#endif\n"
  },
  {
    "path": "bluetoe/filter.hpp",
    "content": "#ifndef BLUETOE_FILTER_HPP\n#define BLUETOE_FILTER_HPP\n\n#include <bluetoe/attribute.hpp>\n#include <bluetoe/bits.hpp>\n#include <bluetoe/uuid.hpp>\n#include <bluetoe/codes.hpp>\n#include <algorithm>\n#include <iterator>\n\nnamespace bluetoe {\nnamespace details {\n\n    /**\n     * @brief filters attributes according to there type\n     */\n    class uuid_filter\n    {\n    public:\n        /**\n         * @brief constructs a filter with a 16 bit or 128 bit, little endian encoded uuid.\n         *\n         * @param bytes points to little endian encode 16 bit or 128 bit uuid\n         * @param true, if bytes point to 128 bit uuid, else false\n         */\n        uuid_filter( const std::uint8_t* bytes, bool is_128bit )\n            : bytes_( bytes )\n            , is_128bit_( is_128bit )\n        {\n            if ( is_128bit && representable_as_16bit_uuid( bytes ) )\n            {\n                // lets treat this uuid as a 16 bit uuid\n                is_128bit_ = false;\n                bytes_    += 12;\n            }\n        }\n\n        bool operator()( std::size_t attribute_index, const attribute& attr ) const\n        {\n            if ( is_128bit_ )\n            {\n                if ( attr.uuid == bits( gatt_uuids::internal_128bit_uuid ) )\n                {\n                    auto compare = attribute_access_arguments::compare_128bit_uuid( bytes_ );\n                    return attr.access( compare, attribute_index ) == attribute_access_result::uuid_equal;\n                }\n                else\n                {\n                    return false;\n                }\n            }\n            else\n            {\n                return read_16bit_uuid( bytes_ ) == attr.uuid;\n            }\n        }\n\n    private:\n        static bool representable_as_16bit_uuid( const std::uint8_t* bytes )\n        {\n            return std::equal( std::begin( bluetooth_base_uuid::bytes ), std::end( bluetooth_base_uuid::bytes ) - 4, bytes )\n                && bytes[ 14 ] == 0 && bytes[ 15 ] == 0;\n        }\n\n        const std::uint8_t* bytes_;\n        bool                is_128bit_;\n    };\n\n    /**\n     * @brief filters a static 16bit uuid\n     *\n     * UUID have to be an instance of details::uuid16\n     * Example:\n     * @code\n    bluetoe::details::uuid16_filter< bluetoe::details::uuid16< 0x2800 > > filter;\n     * @endcode\n     */\n    template < class UUID >\n    struct uuid16_filter;\n\n    template < std::uint64_t UUID, typename Check >\n    struct uuid16_filter< uuid16< UUID, Check > >\n    {\n        constexpr bool operator()( std::size_t, const attribute& attr ) const\n        {\n            return attr.uuid == UUID;\n        }\n    };\n\n    /**\n     * @brief returns every attribute\n     */\n    struct all_uuid_filter\n    {\n        constexpr bool operator()( std::size_t, const details::attribute& ) const\n        {\n            return true;\n        }\n    };\n\n}\n}\n\n#endif\n"
  },
  {
    "path": "bluetoe/find_notification_data.hpp",
    "content": "#ifndef BLUETOE_FIND_NOTIFICATION_DATA_HPP\n#define BLUETOE_FIND_NOTIFICATION_DATA_HPP\n\n#include <bluetoe/meta_tools.hpp>\n\nnamespace bluetoe {\nnamespace details {\n\n    namespace impl {\n        template < typename Characteristics, typename Pair >\n        struct filter_characteristics_with_cccd\n        {\n            using type = typename select_type<\n                Pair::characteristic_t::number_of_client_configs,\n                typename add_type< Characteristics, Pair >::type,\n                Characteristics\n            >::type;\n        };\n\n        template < typename Characteristic, std::size_t Offset, int Prio >\n        struct characteristic_with_service_attribute_offset\n        {\n            using characteristic_t = Characteristic;\n            static constexpr std::size_t   service_offset = Offset;\n            static constexpr int           priority       = Prio;\n        };\n\n        struct preudo_first_char\n        {\n            static constexpr std::size_t number_of_attributes = 0;\n        };\n\n        template < typename Characteristic, std::size_t FirstAttributesIndex, int Prio >\n        struct characteristic_index_pair\n        {\n            using characteristic_t = Characteristic;\n            static constexpr std::size_t   first_attribute_index = FirstAttributesIndex;\n            static constexpr int           priority              = Prio;\n        };\n\n        template < typename Characteristics, typename Characteristic >\n        struct add_index_to_characteristic\n        {\n            using last = typename last_type< Characteristics, impl::characteristic_index_pair< impl::preudo_first_char, 0, 0 > >::type;\n\n            static constexpr std::size_t attribute_handle = last::first_attribute_index + last::characteristic_t::number_of_attributes + Characteristic::service_offset;\n\n            using type = typename add_type<\n                Characteristics,\n                impl::characteristic_index_pair< typename Characteristic::characteristic_t, attribute_handle, Characteristic::priority >\n            >::type;\n        };\n\n        struct attribute_at\n        {\n            constexpr attribute_at( std::size_t& r, std::size_t i )\n                : result( r )\n                , index( i )\n            {}\n\n            template< typename O >\n            void each()\n            {\n                if ( index == 0 )\n                {\n                    result = O::first_attribute_index;\n                }\n\n                --index;\n            }\n\n            std::size_t&    result;\n            std::size_t     index;\n        };\n\n        template < typename A, typename B >\n        struct order_by_prio\n        {\n            using type = std::integral_constant< bool, A::priority < B::priority >;\n        };\n\n        template < typename Characteristics, typename Characteristic >\n        struct add_cccd_position\n        {\n            template < std::size_t CCCD, typename HandlePair >\n            struct with_cccd_position : HandlePair\n            {\n                static constexpr std::size_t cccd_position = CCCD;\n            };\n\n            static constexpr std::size_t cccd_position = std::tuple_size< Characteristics >::value;\n\n            using type = typename add_type<\n                Characteristics,\n                with_cccd_position< cccd_position, Characteristic >\n            >::type;\n        };\n\n        template < typename Characteristics, typename Characteristic >\n        struct add_cccd_handle\n        {\n            template < std::size_t CCCD, typename HandlePair >\n            struct with_cccd_handle : HandlePair\n            {\n                static constexpr std::size_t cccd_handle = CCCD;\n            };\n\n            static constexpr std::size_t cccd_handle = std::tuple_size< Characteristics >::value;\n\n            using type = typename add_type<\n                Characteristics,\n                with_cccd_handle< cccd_handle, Characteristic >\n            >::type;\n        };\n\n        template < class Characteristic >\n        struct select_cccd_position {\n            using type = std::integral_constant< std::size_t, Characteristic::cccd_position >;\n        };\n\n    }\n\n    template <\n        typename Priorities,\n        typename Services\n    >\n    struct find_notification_data_in_list\n    {\n        template < typename Characteristics, typename Service >\n        struct characteristics_from_service\n        {\n            template < typename C >\n            struct add_service_offset\n            {\n                using type = std::tuple<>;\n            };\n\n            // Add just to the first characteritic of a service the numer of attributes that are used to\n            // model the service\n            template < typename C, typename ...Cs >\n            struct add_service_offset< std::tuple< C, Cs... > >\n            {\n                using type = std::tuple<\n                    impl::characteristic_with_service_attribute_offset< C, Service::number_of_service_attributes, Priorities::template characteristic_priority< Services, Service, C >::value >,\n                    impl::characteristic_with_service_attribute_offset< Cs, 0, Priorities::template characteristic_priority< Services, Service, Cs >::value >... >;\n            };\n\n            using type = typename add_type< Characteristics, typename add_service_offset< typename Service::characteristics >::type >::type;\n        };\n\n        using services                               = Services;\n        using all_characteristics                    = typename fold_left< services, characteristics_from_service >::type;\n        using characteristics_with_attribute_indizes = typename fold_left< all_characteristics, impl::add_index_to_characteristic >::type;\n        using characteristics_only_with_cccd         = typename fold_left< characteristics_with_attribute_indizes, impl::filter_characteristics_with_cccd >::type;\n        using characteristics_with_cccd_position     = typename fold_left< characteristics_only_with_cccd, impl::add_cccd_position >::type;\n        using characteristics_sorted_by_priority     = typename stable_sort< impl::order_by_prio, characteristics_with_cccd_position >::type;\n        using characteristics_with_cccd_handle       = typename fold_left< characteristics_sorted_by_priority, impl::add_cccd_handle >::type;\n\n        static notification_data find_notification_data_by_index( std::size_t notification_index )\n        {\n            std::size_t attribute_index = 0;\n            for_< characteristics_sorted_by_priority >::each( impl::attribute_at( attribute_index, notification_index ) );\n\n            return notification_data( attribute_index + 1, notification_index );\n        }\n\n        struct attribute_value\n        {\n            constexpr attribute_value( notification_data& r, const void* v )\n                : result( r )\n                , index( 0 )\n                , value( v )\n            {}\n\n            template< typename O >\n            void each()\n            {\n                if ( O::characteristic_t::value_type::is_this( value ) )\n                    result = notification_data( O::first_attribute_index + 1, index );\n\n                ++index;\n            }\n\n            notification_data&  result;\n            std::size_t         index;\n            const void*         value;\n        };\n\n        static notification_data find_notification_data( const void* value )\n        {\n            notification_data result;\n            for_< characteristics_only_with_cccd >::each( attribute_value( result, value ) );\n\n            return result;\n        }\n\n        using cccd_indices = typename transform_list< characteristics_with_cccd_handle, impl::select_cccd_position >::type;\n    };\n\n    template <\n        typename Priorities,\n        typename Services,\n        typename Characteristic\n    >\n    struct find_notification_by_uuid\n    {\n        using find = find_notification_data_in_list< Priorities, Services >;\n\n        template < typename Other >\n        struct equal_char\n        {\n            static constexpr bool value = std::is_same< typename Other::characteristic_t, Characteristic >::value;\n        };\n\n        using char_infos = typename find_if<\n            typename find::characteristics_with_cccd_handle,\n            equal_char >::type;\n\n        static notification_data data()\n        {\n            return notification_data( char_infos::first_attribute_index + 1, char_infos::cccd_handle );\n        }\n    };\n\n}\n}\n\n#endif\n"
  },
  {
    "path": "bluetoe/gap_service.hpp",
    "content": "#ifndef BLUETOE_GAP_SERVICE_HPP\n#define BLUETOE_GAP_SERVICE_HPP\n\n#include <cstdint>\n#include <bluetoe/service.hpp>\n#include <bluetoe/appearance.hpp>\n#include <bluetoe/server_name.hpp>\n\nnamespace bluetoe {\n\n    namespace details {\n        struct gap_service_definition_meta_type {};\n\n        template < std::uint16_t MinConnectionInterval, std::uint16_t MaxConnectionInterval >\n        struct check_gap_service_for_gatt_servers_parameter\n        {\n\n        };\n    }\n\n    /**\n     * @brief Used as a parameter to a server, to define that the GATT server will _not_ include a GAP service for GATT servers.\n     *\n     * According to BLE 4.2 it's mandatory to have a GAP service for GATT service.\n     * @sa server\n     * @sa gap_service_for_gatt_servers\n     */\n    struct no_gap_service_for_gatt_servers {\n        /** @cond HIDDEN_SYMBOLS */\n        struct meta_type :\n            details::gap_service_definition_meta_type,\n            details::valid_server_option_meta_type {};\n\n        template < typename Services, typename ... ServerOptions >\n        struct add_service {\n            typedef Services type;\n        };\n        /** @endcond */\n    };\n\n    /**\n     * @brief Used as a parameter to a server, to define that the GATT server will include a GAP service for GATT servers.\n     *\n     * This is the default. The GAP Service for GATT Servers is configured directly by passing arguments to the server definition.\n     *\n     * @sa server\n     * @sa appearance\n     * @sa no_gap_service_for_gatt_servers\n     */\n    struct gap_service_for_gatt_servers\n    {\n        /** @cond HIDDEN_SYMBOLS */\n        struct meta_type :\n            details::gap_service_definition_meta_type,\n            details::valid_server_option_meta_type {};\n\n        template < typename Appearance, typename Name >\n        using gap_service =\n            service<\n                service_uuid16< 0x1800 >,\n                characteristic<\n                    characteristic_uuid16< 0x2A00 >,\n                    cstring_wrapper< Name >\n                >,\n                characteristic<\n                    characteristic_uuid16< 0x2A01 >,\n                    fixed_uint16_value< Appearance::value >\n                >\n            >;\n\n        template < typename Services, typename ... ServerOptions >\n        struct add_service {\n            typedef typename details::find_by_meta_type<\n                details::device_appearance_meta_type,\n                ServerOptions...,\n                appearance::unknown\n            >::type device_appearance;\n\n            static constexpr char default_server_name[ 15 ] = \"Bluetoe-Server\";\n\n            typedef typename details::find_by_meta_type<\n                details::server_name_meta_type,\n                ServerOptions...,\n                server_name< default_server_name >\n            >::type device_name;\n\n            typedef typename details::add_type<\n                Services,\n                gap_service< device_appearance, device_name >\n            >::type type;\n        };\n\n        /** @endcond */\n    };\n\n    /** @cond HIDDEN_SYMBOLS */\n    template < typename Services, typename ... ServerOptions >\n    constexpr char gap_service_for_gatt_servers::add_service< Services, ServerOptions... >::default_server_name[ 15 ];\n    /** @endcond */\n\n}\n\n#endif\n"
  },
  {
    "path": "bluetoe/gatt_options.hpp",
    "content": "#ifndef BLUETOE_GATT_OPTIONS_HPP\n#define BLUETOE_GATT_OPTIONS_HPP\n\n#include <bluetoe/meta_types.hpp>\n\n#include <cstdint>\n#include <cstddef>\n\nnamespace bluetoe {\n\n    namespace details {\n        struct mtu_size_meta_type {};\n        struct cccd_callback_meta_type {};\n    }\n\n    /**\n     * @brief define the maximum GATT MTU size to be used\n     *\n     * The default is the minimum of 23.\n     *\n     * @sa server\n     */\n    template < std::uint16_t MaxMTU >\n    struct max_mtu_size {\n        /** @cond HIDDEN_SYMBOLS */\n        struct meta_type :\n            details::mtu_size_meta_type,\n            details::valid_server_option_meta_type {};\n\n        static constexpr std::size_t mtu = MaxMTU;\n        /** @endcond */\n    };\n\n    /**\n     * @brief callback to be called, if the client characteristic configuration has changed\n     *        or was written.\n     *\n     * The provided callback type T must be a class with the following public accessible function:\n     *\n     * @code\n     * template < class Server >\n     * void client_characteristic_configuration_updated( Server&, const client_characteristic_configuration& );\n     * @endcode\n     *\n     * Where Server is the configured instance of a `bluetoe::server<>` instance.\n     */\n    template < typename T, T& Obj >\n    struct client_characteristic_configuration_update_callback\n    {\n        /** @cond HIDDEN_SYMBOLS */\n        struct meta_type :\n            details::cccd_callback_meta_type,\n            details::valid_server_option_meta_type {};\n\n        template < class Server >\n        static void client_characteristic_configuration_updated( Server& srv, const bluetoe::details::client_characteristic_configuration& data )\n        {\n            Obj.client_characteristic_configuration_updated( srv, data );\n        }\n        /** @endcond */\n    };\n\n    /** @cond HIDDEN_SYMBOLS */\n    struct no_client_characteristic_configuration_update_callback\n    {\n        struct meta_type :\n            details::cccd_callback_meta_type,\n            details::valid_server_option_meta_type {};\n\n        template < class Server >\n        static void client_characteristic_configuration_updated( Server&, const bluetoe::details::client_characteristic_configuration& )\n        {\n        }\n    };\n    /** @endcond */\n}\n\n#endif"
  },
  {
    "path": "bluetoe/hci/CMakeLists.txt",
    "content": "add_library(bluetoe_hci INTERFACE)\n\nadd_library(bluetoe::hci ALIAS bluetoe_hci)\n\ntarget_include_directories(bluetoe_hci INTERFACE include)\n# target_compile_features(bluetoe_hci PRIVATE cxx_std_11)\n# target_compile_options(bluetoe_hci PRIVATE -Wall -pedantic -Wextra -Wfatal-errors)\n"
  },
  {
    "path": "bluetoe/hci/include/bluetoe/link_layer.hpp",
    "content": "#ifndef BLUETOE_HCI_LINK_LAYER_HPP\n#define BLUETOE_HCI_LINK_LAYER_HPP\n\n#include <bluetoe/address.hpp>\n\nnamespace bluetoe {\nnamespace hci {\n\n    /**\n     * @brief link layer implementation based on HCI\n     */\n    template <\n        class Server,\n        template < typename >\n        class Transport,\n        typename ... Options\n    >\n    class link_layer : Transport< link_layer< Server, Transport, Options... > >\n    {\n    public:\n        /**\n         * @brief this function passes the CPU to the link layer implementation\n         *\n         * This function should return on certain events to alow user code to do\n         * usefull things. Details depend on the ScheduleRadio implemention.\n         */\n        void run( Server& );\n\n        /**\n         * @brief initiating the change of communication parameters of an established connection\n         *\n         * If it was not possible to initiate the connection parameter update, the function returns false.\n         * @todo Add parameter that identifies the connection.\n         */\n        bool connection_parameter_update_request( std::uint16_t interval_min, std::uint16_t interval_max, std::uint16_t latency, std::uint16_t timeout );\n\n        /**\n         * @brief terminates the give connection\n         *\n         * @todo Add parameter that identifies the connection.\n         */\n        void disconnect();\n\n        /**\n         * @brief fills the given buffer with l2cap advertising payload\n         */\n        std::size_t fill_l2cap_advertising_data( std::uint8_t* buffer, std::size_t buffer_size ) const;\n\n        /**\n         * @brief returns the own local device address\n         */\n        const bluetoe::link_layer::device_address& local_address() const;\n    private:\n    };\n\n    // implementation\n    template < class Server, template < typename > class Transport, typename ... Options >\n    void link_layer< Server, Transport, Options... >::run( Server& )\n    {\n    }\n}\n}\n\n#endif\n"
  },
  {
    "path": "bluetoe/l2cap.hpp",
    "content": "#ifndef BLUETOE_L2CAP_HPP\n#define BLUETOE_L2CAP_HPP\n\n#include <cstdint>\n#include <cstddef>\n#include <cassert>\n\n#include <bluetoe/codes.hpp>\n#include <bluetoe/meta_tools.hpp>\n#include <bluetoe/bits.hpp>\n\n/*\n * Design decisions:\n * - Link layer should not know nothing about l2cap fragmentation / channels and so on\n * - L2CAP layer should not know anything about LL PDU layouts\n * - link_layer::read_buffer / link_layer::read_buffer should be assigned to LL PDUs and their\n *   layout and thus, not be used in the l2cap layer.\n * - For now, the fragmentation, defragmentation is still done in the ll_l2cap_sdu_buffer\n *   of the link_layer, but should be moved into the l2cap<> class.\n */\nnamespace bluetoe {\n\nnamespace details {\n\n    /**\n     * @brief this class documents the requirements of a single l2cap channel to satisfy\n     *        the requirements of the l2cap<> class.\n     */\n    class l2cap_channel\n    {\n    public:\n        static constexpr std::uint16_t channel_id = 42;\n        static constexpr std::size_t   minimum_channel_mtu_size = bluetoe::details::default_att_mtu_size;\n        static constexpr std::size_t   maximum_channel_mtu_size = bluetoe::details::default_att_mtu_size;\n\n        template < typename ConnectionData >\n        void l2cap_input( const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size, ConnectionData& );\n\n        template < typename ConnectionData >\n        void l2cap_output( std::uint8_t* output, std::size_t& out_size, ConnectionData& );\n\n        template < class PreviousData >\n        using channel_data_t = PreviousData;\n    };\n\n    template < typename CurrentMaximum, typename Channel >\n    struct maximum_min_channel_mtu_size\n    {\n        using type =\n            typename select_type<\n                ( CurrentMaximum::value > Channel::minimum_channel_mtu_size ),\n                CurrentMaximum,\n                std::integral_constant< std::size_t, Channel::minimum_channel_mtu_size >\n            >::type;\n    };\n\n    template < typename CurrentMaximum, typename Channel >\n    struct maximum_max_channel_mtu_size\n    {\n        using type =\n            typename select_type<\n                ( CurrentMaximum::value > Channel::maximum_channel_mtu_size ),\n                CurrentMaximum,\n                std::integral_constant< std::size_t, Channel::maximum_channel_mtu_size >\n            >::type;\n    };\n\n    template < typename ComposedData, typename Channel >\n    struct add_channel_data\n    {\n        using type = typename Channel::template channel_data_t< ComposedData >;\n    };\n\n    static constexpr std::size_t l2cap_layer_header_size = 4u;\n\n    /**\n     * @brief l2cap layer, as list of l2cap channels\n     *\n     * The interface between link_layer and l2cap is designed, so that\n     * both parts could be run in different CPU contexts. This basically means,\n     * that the reponse to an incomming PDU must be able to be defered. That's\n     * why the functions do not directly return the result of the L2CAP request,\n     * but use the output parameters to allocate buffers and commit that buffers.\n     *\n     * LinkLayer derives from l2cap<> and provides following functions:\n     *\n     * - std::pair< std::size_t, std::uint8_t* > allocate_l2cap_output_buffer( std::size_t )\n     *\n     *   This function is used to allocate outgoing capacity. If the function can not provide\n     *   the requested size, it has to provide { 0, nullptr }.\n     *\n     * - void commit_l2cap_output_buffer( std::pair< std::size_t, std::uint8_t* > )\n     *\n     *   This function is used to commit the allocated output buffer.\n     */\n    template < class LinkLayer, class ChannelData, class ... Channels >\n    class l2cap : public derive_from< std::tuple< Channels... > >\n    {\n    public:\n        /**\n         * @ret true, if the passed input was consumed\n         */\n        template < class ConnectionDetails >\n        bool handle_l2cap_input( const std::uint8_t* input, std::size_t in_size, ConnectionDetails& connection );\n\n        /**\n         * @brief function to be called one every connection event, from the link layer\n         *        to collect outstanding responses.\n         */\n        template < class ConnectionDetails >\n        void transmit_pending_l2cap_output( ConnectionDetails& connection );\n\n        /**\n         * @brief the minimum MTU size, that is required by all L2CAP channels\n         *\n         * This is the size without the 4 byte L2CAP header.\n         */\n        static constexpr std::size_t minimum_mtu_size = fold<\n            std::tuple< Channels... >,\n            maximum_min_channel_mtu_size,\n            std::integral_constant< std::size_t, 0 >\n        >::type::value;\n\n        static constexpr std::size_t maximum_mtu_size = fold<\n            std::tuple< Channels... >,\n            maximum_max_channel_mtu_size,\n            std::integral_constant< std::size_t, 0 >\n        >::type::value;\n\n        static_assert( maximum_mtu_size >= minimum_mtu_size, \"maximum_mtu_size have to be greater than minimum_mtu_size\" );\n\n        using connection_data_t = typename fold<\n            std::tuple< Channels... >,\n            add_channel_data,\n            ChannelData\n        >::type;\n\n    private:\n        template < class ConnectionDetails >\n        bool transmit_single_pending_l2cap_output( ConnectionDetails& connection );\n\n        template < class ConnectionDetails >\n        struct l2cap_input_handler\n        {\n            l2cap_input_handler( l2cap* t, std::uint16_t ci, const std::uint8_t* i, std::size_t is, std::uint8_t* o, std::size_t os, ConnectionDetails& c )\n                : that( t )\n                , channel_id( ci )\n                , input( i )\n                , in_size( is )\n                , output( o )\n                , out_size( os )\n                , connection( c )\n                , handled( false )\n            {\n            }\n\n            template< typename Channel >\n            void each()\n            {\n                if ( channel_id == Channel::channel_id )\n                {\n                    static_cast< Channel& >( *that ).l2cap_input( input, in_size, output, out_size, connection );\n                    handled = true;\n                }\n            }\n\n            l2cap*                      that;\n            std::uint16_t               channel_id;\n            const std::uint8_t*         input;\n            std::size_t                 in_size;\n            std::uint8_t*               output;\n            std::size_t                 out_size;\n            ConnectionDetails&          connection;\n            bool                        handled;\n        };\n\n        template < typename ConnectionDetails >\n        class l2cap_output_handler\n        {\n        public:\n            l2cap_output_handler( l2cap* t, std::uint8_t* out, std::size_t s, ConnectionDetails& c )\n                : that( t )\n                , output( out )\n                , size( s )\n                , out_size( 0 )\n                , connection( c )\n            {\n            }\n\n            template< typename Channel >\n            void each()\n            {\n                if ( out_size == 0 )\n                {\n                    out_size = size;\n                    static_cast< Channel& >( *that ).l2cap_output( output, out_size, connection );\n                    channel_id = Channel::channel_id;\n                }\n            }\n\n            l2cap*              that;\n            std::uint8_t*       output;\n            std::size_t         size;\n            std::size_t         out_size;\n            std::uint16_t       channel_id;\n            ConnectionDetails&  connection;\n        };\n\n        LinkLayer& link_layer()\n        {\n            return static_cast< LinkLayer&>( *this );\n        }\n    };\n\n\n    // implemenation\n    template < class LinkLayer, class ChannelData, class ... Channels >\n    template < class ConnectionDetails >\n    bool l2cap< LinkLayer, ChannelData, Channels... >::handle_l2cap_input( const std::uint8_t* input, std::size_t in_size, ConnectionDetails& connection )\n    {\n        // just swallow input, if not resonable\n        if ( in_size < l2cap_layer_header_size )\n            return true;\n\n        const std::uint16_t size       = read_16bit( input );\n        const std::uint16_t channel_id = read_16bit( input + 2 );\n\n        if ( in_size != size + l2cap_layer_header_size )\n            return true;\n\n        auto output = link_layer().allocate_l2cap_output_buffer( maximum_mtu_size );\n        if ( output.first == 0 )\n            return false;\n\n        assert( output.second );\n\n        l2cap_input_handler< ConnectionDetails > handler(\n            this, channel_id, input + l2cap_layer_header_size, in_size - l2cap_layer_header_size,\n            output.second + l2cap_layer_header_size, maximum_mtu_size, connection );\n\n        for_< Channels... >::template each< l2cap_input_handler< ConnectionDetails >& >( handler );\n\n        if ( handler.handled && handler.out_size )\n        {\n            write_16bit( output.second,  handler.out_size );\n            write_16bit( output.second + 2, channel_id );\n            link_layer().commit_l2cap_output_buffer( {  handler.out_size + l2cap_layer_header_size, output.second } );\n        }\n\n        return true;\n    }\n\n    template < class LinkLayer, class ChannelData, class ... Channels >\n    template < class ConnectionDetails >\n    void l2cap< LinkLayer, ChannelData, Channels... >::transmit_pending_l2cap_output( ConnectionDetails& connection )\n    {\n        for ( bool cont = transmit_single_pending_l2cap_output( connection ); cont;\n                cont = transmit_single_pending_l2cap_output( connection ) )\n            ;\n    }\n\n    template < class LinkLayer, class ChannelData, class ... Channels >\n    template < class ConnectionDetails >\n    bool l2cap< LinkLayer, ChannelData, Channels... >::transmit_single_pending_l2cap_output( ConnectionDetails& connection )\n    {\n        auto output = link_layer().allocate_l2cap_output_buffer( maximum_mtu_size );\n        if ( output.first == 0 )\n            return false;\n\n        assert( output.second );\n\n        l2cap_output_handler< ConnectionDetails > handler(\n            this, output.second + l2cap_layer_header_size, output.first - l2cap_layer_header_size, connection );\n\n        for_< Channels... >::template each< l2cap_output_handler< ConnectionDetails >& >( handler );\n\n        if ( handler.out_size )\n        {\n            write_16bit( output.second, handler.out_size );\n            write_16bit( output.second + 2, handler.channel_id );\n            link_layer().commit_l2cap_output_buffer( { handler.out_size + l2cap_layer_header_size, output.second } );\n        }\n\n        return handler.out_size;\n    }\n}\n}\n\n#endif\n"
  },
  {
    "path": "bluetoe/l2cap_channels.hpp",
    "content": "#ifndef BLUETOE_L2CAP_CHANNELS_HPP\n#define BLUETOE_L2CAP_CHANNELS_HPP\n\nnamespace bluetoe {\n\n    namespace l2cap_channel_ids {\n        /**\n         * @brief currently supported LE L2CAP channels\n         */\n        enum l2cap_channel_ids : std::uint16_t {\n            att             = 4,\n            signaling       = 5,\n            sm              = 6\n        };\n    }\n}\n\n#endif\n"
  },
  {
    "path": "bluetoe/link_layer/CMakeLists.txt",
    "content": "add_library(bluetoe_linklayer STATIC\n            delta_time.cpp\n            channel_map.cpp\n            connection_details.cpp)\n\nadd_library(bluetoe::link_layer ALIAS bluetoe_linklayer)\n\ntarget_include_directories(bluetoe_linklayer PUBLIC include)\ntarget_link_libraries(bluetoe_linklayer PUBLIC bluetoe::utility bluetoe::sm bluetoe::iface)\ntarget_compile_features(bluetoe_linklayer PRIVATE cxx_std_11)\ntarget_compile_options(bluetoe_linklayer PRIVATE -Wall -pedantic -Wextra -Wfatal-errors)\n"
  },
  {
    "path": "bluetoe/link_layer/channel_map.cpp",
    "content": "#include <bluetoe/channel_map.hpp>\n#include <cassert>\n\nnamespace bluetoe {\nnamespace link_layer {\n\n    channel_map::channel_map()\n        : hop_( 0 )\n    {\n    }\n\n    static bool in_map( const std::uint8_t* map, unsigned index )\n    {\n        return map[ index / 8 ] & ( 1 << ( index % 8 ) );\n    }\n\n    unsigned channel_map::build_used_channel_map( const std::uint8_t* map, std::uint8_t* used ) const\n    {\n        unsigned count = 0;\n\n        for ( unsigned channel = 0; channel != max_number_of_data_channels; ++channel )\n        {\n            if ( in_map( map, channel ) )\n            {\n                used[ count ] = channel;\n                ++count;\n            }\n        }\n\n        return count;\n    }\n\n    bool channel_map::reset( const std::uint8_t* map, const unsigned hop )\n    {\n        assert( map );\n\n        if ( hop < 5 || hop > 16 )\n            return false;\n\n        hop_ = hop;\n\n        std::uint8_t   used_channels[ max_number_of_data_channels ];\n        const unsigned used_channels_count = build_used_channel_map( map, used_channels );\n\n        if ( used_channels_count < 2 )\n            return false;\n\n        for ( unsigned index = 0, channel = hop; index != max_number_of_data_channels; ++index )\n        {\n            if ( in_map( map, channel ) )\n            {\n                map_[ index ] = channel;\n            }\n            else\n            {\n                map_[ index ] = used_channels[ channel % used_channels_count ];\n            }\n\n            channel = ( channel + hop ) % max_number_of_data_channels;\n        }\n\n        return true;\n    }\n\n    bool channel_map::reset( const std::uint8_t* map )\n    {\n        return reset( map, hop_ );\n    }\n\n    unsigned channel_map::data_channel( unsigned index ) const\n    {\n        assert( index < max_number_of_data_channels );\n        return map_[ index ];\n    }\n\n\n}\n}\n"
  },
  {
    "path": "bluetoe/link_layer/connection_details.cpp",
    "content": "#include <bluetoe/connection_details.hpp>\n\nnamespace bluetoe {\nnamespace link_layer {\n\n    connection_details::connection_details(\n        const channel_map& channels,\n        std::uint16_t inter, std::uint16_t lat, std::uint16_t to,\n        unsigned acc )\n        : channels_( channels )\n        , interval_( inter )\n        , latency_( lat )\n        , timeout_( to )\n        , accuracy_( acc )\n    {\n    }\n\n    const channel_map& connection_details::channels() const\n    {\n        return channels_;\n    }\n\n    std::uint16_t connection_details::interval() const\n    {\n        return interval_;\n    }\n\n    std::uint16_t connection_details::latency() const\n    {\n        return latency_;\n    }\n\n    std::uint16_t connection_details::timeout() const\n    {\n        return timeout_;\n    }\n\n    unsigned connection_details::cumulated_sleep_clock_accuracy_ppm() const\n    {\n        return accuracy_;\n    }\n\n\n    connection_addresses::connection_addresses( const device_address& local, const device_address& remote )\n        : local_addr_( local )\n        , remote_addr_( remote )\n    {\n    }\n\n    const device_address& connection_addresses::remote_address() const\n    {\n        return remote_addr_;\n    }\n\n    const device_address& connection_addresses::local_address() const\n    {\n        return local_addr_;\n    }\n}\n}\n"
  },
  {
    "path": "bluetoe/link_layer/delta_time.cpp",
    "content": "#include <bluetoe/delta_time.hpp>\n#include <ostream>\n#include <cassert>\n\nnamespace bluetoe {\nnamespace link_layer {\n\n    delta_time delta_time::usec( std::uint32_t usec )\n    {\n        return delta_time( usec );\n    }\n\n    delta_time delta_time::msec( std::uint32_t msec )\n    {\n        std::uint32_t usec = msec * 1000;\n        assert( usec >= msec );\n\n        return delta_time( usec );\n    }\n\n    delta_time delta_time::seconds( int s )\n    {\n        return delta_time( s * 1000 * 1000 );\n    }\n\n    delta_time delta_time::now()\n    {\n        return delta_time( 0 );\n    }\n\n    void delta_time::print( std::ostream& output ) const\n    {\n        if ( usec_ == 0 || usec_ % 1000 == 0 )\n            output << ( usec_ / 1000 ) << \"ms\";\n        else\n            output << usec_ << \"µs\";\n    }\n\n    delta_time& delta_time::operator+=( const delta_time& rhs )\n    {\n        auto const sum = usec_ + rhs.usec_;\n        assert( sum >= usec_ && sum >= rhs.usec_ );\n\n        usec_ = sum;\n\n        return *this;\n    }\n\n    delta_time& delta_time::operator-=( const delta_time& rhs )\n    {\n        auto const diff = usec_ - rhs.usec_;\n        assert( diff <= usec_ );\n\n        usec_ = diff;\n\n        return *this;\n    }\n\n    delta_time& delta_time::operator*=( unsigned rhs )\n    {\n        if ( rhs == 0 || usec_ == 0 )\n        {\n            usec_ = 0;\n        }\n        else if ( rhs > 1 )\n        {\n            if ( usec_ == 1 )\n            {\n                usec_ = rhs;\n            }\n            else\n            {\n                auto const prod = usec_ * rhs;\n                assert( prod > usec_ );\n                assert( prod > rhs );\n\n                usec_ = prod;\n            }\n        }\n\n        return *this;\n    }\n\n    unsigned delta_time::operator/(const delta_time& rhs )\n    {\n        assert( rhs.usec_ );\n        return usec_ / rhs.usec_;\n    }\n\n    bool delta_time::operator<( const delta_time& rhs ) const\n    {\n        return usec_ < rhs.usec_;\n    }\n\n    bool delta_time::operator<=( const delta_time& rhs ) const\n    {\n        return usec_ <= rhs.usec_;\n    }\n\n    bool delta_time::operator>( const delta_time& rhs ) const\n    {\n        return usec_ > rhs.usec_;\n    }\n\n    bool delta_time::operator>=( const delta_time& rhs ) const\n    {\n        return usec_ >= rhs.usec_;\n    }\n\n    bool delta_time::operator==( const delta_time& rhs ) const\n    {\n        return usec_ == rhs.usec_;\n    }\n\n    bool delta_time::operator!=( const delta_time& rhs ) const\n    {\n        return usec_ != rhs.usec_;\n    }\n\n    std::uint32_t delta_time::usec() const\n    {\n        return usec_;\n    }\n\n    bool delta_time::zero() const\n    {\n        return usec_ == 0;\n    }\n\n    delta_time delta_time::ppm( unsigned part ) const\n    {\n        /*\n         * Assumed that usec_ is at most 10^8 and the multiplication is done in a 64 bit\n         * integer, the result will be in the order 10^8 * 1000 = 10^11 ~ 2^37,\n         * the result can be scalled by 2^27 before shifting it to the right by 2^47\n         */\n        return delta_time( ( std::uint64_t( usec_ ) * part * 140737488 ) >> 47 );\n    }\n\n    std::ostream& operator<<( std::ostream& out, const delta_time& t )\n    {\n        t.print( out );\n\n        return out;\n    }\n\n    delta_time operator+( delta_time lhs, delta_time rhs )\n    {\n        lhs += rhs;\n        return lhs;\n    }\n\n    delta_time operator-( delta_time lhs, delta_time rhs )\n    {\n        lhs-= rhs;\n        return lhs;\n    }\n\n    delta_time operator*( delta_time lhs, unsigned rhs )\n    {\n        lhs *= rhs;\n        return lhs;\n    }\n\n    delta_time operator*( unsigned lhs, delta_time rhs )\n    {\n        rhs *= lhs;\n        return rhs;\n    }\n\n}\n}\n"
  },
  {
    "path": "bluetoe/link_layer/include/bluetoe/advertising.hpp",
    "content": "#ifndef BLUETOE_LINK_LAYER_ADVERTISING_HPP\n#define BLUETOE_LINK_LAYER_ADVERTISING_HPP\n\n#include <bluetoe/meta_tools.hpp>\n#include <bluetoe/default_pdu_layout.hpp>\n#include <bluetoe/address.hpp>\n#include <bluetoe/buffer.hpp>\n#include <bluetoe/delta_time.hpp>\n#include <bluetoe/ll_meta_types.hpp>\n\n/**\n * @file bluetoe/link_layer/include/bluetoe/advertising.hpp\n *\n * Design criterias for advertising:\n * - resonable default (connectable undirected adv.)\n * - no overhead if defaults are used\n * - configurable advertising interval\n * - advertising count implementable\n */\n\nnamespace bluetoe {\nnamespace link_layer {\n\n    namespace details {\n        struct advertising_type_meta_type {};\n        struct advertising_startup_meta_type {};\n        struct advertising_interval_meta_type {};\n        struct advertising_channel_map_meta_type {};\n\n        template < unsigned long long AdvertisingIntervalMilliSeconds >\n        struct check_advertising_interval_parameter {\n            static_assert( AdvertisingIntervalMilliSeconds >= 20,    \"the advertising interval must be greater than or equal to 20ms.\" );\n            static_assert( AdvertisingIntervalMilliSeconds <= 10240, \"the advertising interval must be smaller than or equal to 10.24s.\" );\n\n            typedef void type;\n        };\n\n        struct advertising_type_base {\n            static constexpr std::uint8_t   header_txaddr_field         = 0x40;\n            static constexpr std::uint8_t   header_rxaddr_field         = 0x80;\n            static constexpr std::size_t    advertising_pdu_header_size = 2;\n            static constexpr std::uint8_t   adv_ind_pdu_type_code       = 0;\n            static constexpr std::uint8_t   adv_direct_ind_pdu_type_code= 1;\n            static constexpr std::uint8_t   adv_nonconn_ind_pdu_type_code= 2;\n            static constexpr std::uint8_t   adv_scan_ind_pdu_type_code  = 6;\n            static constexpr std::uint8_t   scan_response_pdu_type_code = 4;\n            static constexpr std::size_t    address_length              = 6;\n            static constexpr std::size_t    maximum_adv_request_size    = 34;\n\n            static constexpr std::size_t    max_advertising_data_size   = 31;\n            static constexpr std::size_t    max_scan_response_data_size = 31;\n\n            static constexpr std::size_t    max_advertising_pdu_size   = max_advertising_data_size + address_length;\n            static constexpr std::size_t    max_scan_response_pdu_size = max_scan_response_data_size + address_length;\n\n            template < typename Layout >\n            static bool is_valid_scan_request( const read_buffer& receive, const device_address& addr )\n            {\n                static constexpr std::size_t  scan_request_size = 2 * address_length;\n                static constexpr std::uint8_t scan_request_code = 0x03;\n\n                const std::uint16_t header = Layout::header( receive );\n\n                bool result = receive.size == Layout::data_channel_pdu_memory_size( scan_request_size )\n                    && ( ( header >> 8 ) & 0x3f ) == scan_request_size\n                    && ( header & 0x0f ) == scan_request_code;\n\n                if ( result )\n                {\n                    const auto body = Layout::body( receive );\n                    result = result && std::equal( &body.begin[ address_length ], &body.begin[ 2 * address_length ], addr.begin() );\n                    result = result && addr.is_random() == ( ( header & header_rxaddr_field ) != 0 );\n                }\n\n                return result;\n            }\n\n            template < typename Layout >\n            static bool is_valid_connect_request( const read_buffer& receive, const device_address& addr )\n            {\n                static constexpr std::size_t  connect_request_size = 34;\n                static constexpr std::uint8_t connect_request_code = 0x05;\n\n                if ( receive.size != Layout::data_channel_pdu_memory_size( connect_request_size ) )\n                    return false;\n\n                const std::uint16_t header = Layout::header( receive );\n                const auto          body   = Layout::body( receive ).first;\n\n                bool result = ( ( header >> 8 ) & 0x3f ) == connect_request_size\n                           && ( header & 0x0f ) == connect_request_code;\n\n                result = result && std::equal( &body[ address_length ], &body[ 2 * address_length ], addr.begin() );\n                result = result && addr.is_random() == ( ( header & header_rxaddr_field ) != 0 );\n\n                return result;\n            }\n\n            template < typename Layout >\n            static std::size_t fill_empty_scan_response_data( const device_address& addr, read_buffer adv_response_buffer )\n            {\n                std::uint16_t header = scan_response_pdu_type_code;\n\n                if ( addr.is_random() )\n                    header |= header_txaddr_field;\n\n                static constexpr std::size_t empty_ad_size = 2;\n                std::size_t adv_response_size = advertising_pdu_header_size + address_length + empty_ad_size;\n                header |= ( adv_response_size - advertising_pdu_header_size ) << 8;\n\n                const auto body = Layout::body( adv_response_buffer );\n\n                std::copy( addr.begin(), addr.end(), body.first );\n\n                // add aditional empty AD to be visible to Nordic sniffer.\n                // Some stacks do not recognize the response without this empty AD.\n                body.first[ adv_response_size - 2 ] = 0;\n                body.first[ adv_response_size - 1 ] = 0;\n\n                Layout::header( adv_response_buffer, header );\n\n                return adv_response_size;\n            }\n        };\n    }\n\n\n    /**\n     * @example change_advertising_example.cpp\n     *\n     * This example demonstrates how to change the advertising type. The link layer is configured to support\n     * two different advertising types (bluetoe::link_layer::connectable_undirected_advertising and bluetoe::link_layer::connectable_directed_advertising).\n     * Now, the change_advertising() function can be used to switch between both advertising types.\n     */\n\n    /**\n     * @brief enables connectable undirected advertising\n     *\n     * If no advertising type is specified, this will be the\n     * default.\n     *\n     * @sa connectable_directed_advertising\n     * @sa scannable_undirected_advertising\n     * @sa non_connectable_undirected_advertising\n     */\n    class connectable_undirected_advertising\n    {\n    public:\n        /**\n         * @brief change type of advertisment\n         *\n         * If more than one advertising type is given, this function can be used\n         * to define the advertising that is used next, when the device starts\n         * advertising. If the device is currently advertising, the function\n         * has no effect until the device stops advertising and starts over to\n         * advertise.\n         *\n         * @tparam Type the next type of advertising\n         */\n        template < typename Type >\n        void change_advertising();\n\n        /** @cond HIDDEN_SYMBOLS */\n        struct meta_type :\n            details::advertising_type_meta_type,\n            details::valid_link_layer_option_meta_type {};\n\n        template < typename LinkLayer, typename Advertiser >\n        class impl : protected details::advertising_type_base\n        {\n        protected:\n            read_buffer fill_advertising_data()\n            {\n                using layout_t = typename pdu_layout_by_radio< typename LinkLayer::radio_t >::pdu_layout;\n                const device_address& addr = link_layer().local_address();\n\n                // prevent assert() in layout_t::body\n                adv_size_ = address_length;\n\n                const auto buffer = advertiser().advertising_buffer();\n                std::uint16_t header = adv_ind_pdu_type_code;\n                std::uint8_t* body   = layout_t::body( buffer ).first;\n\n                if ( addr.is_random() )\n                    header |= header_txaddr_field;\n\n                const std::size_t size =\n                    address_length\n                  + link_layer().fill_l2cap_advertising_data( &body[ address_length ], max_advertising_data_size );\n\n                header   |= size << 8;\n                adv_size_ = layout_t::data_channel_pdu_memory_size( size );\n\n                std::copy( addr.begin(), addr.end(), body );\n                layout_t::header( buffer, header );\n\n                fill_scan_response_data();\n                return buffer;\n            }\n\n            read_buffer get_advertising_data()\n            {\n                return advertiser().advertising_buffer();\n            }\n\n            read_buffer get_scan_response_data()\n            {\n                return advertiser().scan_response_buffer();\n            }\n\n            bool is_valid_scan_request( const read_buffer& receive ) const\n            {\n                using layout_t = typename pdu_layout_by_radio< typename LinkLayer::radio_t >::pdu_layout;\n                return details::advertising_type_base::is_valid_scan_request< layout_t >( receive, link_layer().local_address() );\n            }\n\n            bool is_valid_connect_request( const read_buffer& receive ) const\n            {\n                using layout_t = typename pdu_layout_by_radio< typename LinkLayer::radio_t >::pdu_layout;\n                return details::advertising_type_base::is_valid_connect_request< layout_t >( receive, link_layer().local_address() );\n            }\n\n        private:\n\n            static constexpr std::size_t    maximum_adv_send_size       = max_advertising_data_size + address_length;\n\n            void fill_scan_response_data()\n            {\n                using layout_t = typename pdu_layout_by_radio< typename LinkLayer::radio_t >::pdu_layout;\n                const device_address& addr = link_layer().local_address();\n\n                const auto buffer = advertiser().scan_response_buffer();\n\n                std::uint16_t header = scan_response_pdu_type_code;\n                std::uint8_t* body   = layout_t::body( buffer ).first;\n\n                if ( addr.is_random() )\n                    header |= header_txaddr_field;\n\n                const std::size_t size =\n                    address_length\n                  + link_layer().fill_l2cap_scan_response_data( &body[ address_length ], max_scan_response_data_size );\n\n                header   |= size << 8;\n                adv_response_size_ = layout_t::data_channel_pdu_memory_size( size );\n\n                std::copy( addr.begin(), addr.end(), body );\n                layout_t::header( buffer, header );\n            }\n\n            LinkLayer& link_layer()\n            {\n                return static_cast< LinkLayer& >( *this );\n            }\n\n            const LinkLayer& link_layer() const\n            {\n                return static_cast< const LinkLayer& >( *this );\n            }\n\n            Advertiser& advertiser()\n            {\n                return static_cast< Advertiser& >( *this );\n            }\n\n            std::size_t                     adv_size_;\n            std::size_t                     adv_response_size_;\n\n        };\n        /** @endcond */\n    };\n\n    /**\n     * @brief enables low duty connectable directed advertising\n     *\n     * When using directed advertising, advertising starts, when\n     * no connection is established and and the directed_advertising_address()\n     * function was called.\n     *\n     * @sa connectable_undirected_advertising\n     * @sa scannable_undirected_advertising\n     * @sa non_connectable_undirected_advertising\n     */\n    class connectable_directed_advertising\n    {\n    public:\n        /**\n         * @brief change type of advertisment\n         *\n         * If more than one advertising type is given, this function can be used\n         * to define the advertising that is used next, when the device starts\n         * advertising. If the device is currently advertising, the function\n         * has no effect until the device stops advertising and starts over to\n         * advertise.\n         *\n         * @tparam Type the next type of advertising\n         */\n        template < typename Type >\n        void change_advertising();\n\n        /**\n         * @brief sets the address to be used in the advertising\n         *        PDU.\n         *\n         * Starts advertising if an address was not set before.\n         */\n        void directed_advertising_address( const device_address& addr );\n\n        /** @cond HIDDEN_SYMBOLS */\n        struct meta_type :\n            details::advertising_type_meta_type,\n            details::valid_link_layer_option_meta_type {};\n\n        template < typename LinkLayer, typename Advertiser >\n        class impl : protected details::advertising_type_base\n        {\n        public:\n            void directed_advertising_address( const device_address& addr )\n            {\n                bool address_valid     = addr != device_address();\n                bool start_advertising = !addr_valid_ && address_valid;\n\n                addr_       = addr;\n                addr_valid_ = address_valid;\n\n                if ( start_advertising && started_ )\n                    advertiser().handle_start_advertising();\n            }\n\n        protected:\n            impl()\n                : addr_valid_( false )\n                , started_( false )\n            {\n            }\n\n            read_buffer fill_advertising_data()\n            {\n                if ( !addr_valid_ )\n                {\n                    started_ = true;\n                    return read_buffer{ nullptr, 0 };\n                }\n\n                const device_address& addr = link_layer().local_address();\n                using layout_t = typename pdu_layout_by_radio< typename LinkLayer::radio_t >::pdu_layout;\n\n                const auto buffer = advertiser().advertising_buffer();\n\n                std::uint8_t* const adv_data = buffer.buffer;\n                std::uint16_t header = adv_direct_ind_pdu_type_code;\n\n                if ( addr.is_random() )\n                    header |= header_txaddr_field;\n\n                if ( addr_.is_random() )\n                    header |= header_rxaddr_field;\n\n                header |= ( 2 * address_length ) << 8;\n\n                layout_t::header( adv_data, header );\n\n                const auto body = layout_t::body( buffer );\n                std::copy( addr.begin(), addr.end(), &body.first[ 0 ] );\n                std::copy( addr_.begin(), addr_.end(), &body.first[ address_length ] );\n\n                return buffer;\n            }\n\n            read_buffer get_advertising_data()\n            {\n                return addr_valid_ ? advertiser().advertising_buffer() : read_buffer{ nullptr, 0 };\n            }\n\n            read_buffer get_scan_response_data() const\n            {\n                return read_buffer{ nullptr, 0 };\n            }\n\n            bool is_valid_scan_request( const read_buffer& ) const\n            {\n                return false;\n            }\n\n            bool is_valid_connect_request( const read_buffer& receive ) const\n            {\n                using layout_t = typename pdu_layout_by_radio< typename LinkLayer::radio_t >::pdu_layout;\n\n                bool result = details::advertising_type_base::is_valid_connect_request< layout_t >( receive, link_layer().local_address() );\n                const auto body   = layout_t::body( receive ).first;\n                const auto header = layout_t::header( receive );\n\n                result = result && std::equal( &body[ 0 ], &body[ address_length ], addr_.begin() ) && addr_valid_;\n                result = result && addr_.is_random() == ( ( header & header_txaddr_field ) != 0 );\n\n                return result;\n            }\n\n        private:\n\n            static constexpr std::size_t    max_advertising_data_size   = 2 * address_length;\n\n            LinkLayer& link_layer()\n            {\n                return static_cast< LinkLayer& >( *this );\n            }\n\n            const LinkLayer& link_layer() const\n            {\n                return static_cast< const LinkLayer& >( *this );\n            }\n\n            Advertiser& advertiser()\n            {\n                return static_cast< Advertiser& >( *this );\n            }\n\n            device_address  addr_;\n            bool            addr_valid_;\n            bool            started_;\n        };\n        /** @endcond */\n    };\n\n    /**\n     * @brief enables scannable undirected advertising\n     *\n     * @sa connectable_undirected_advertising\n     * @sa connectable_directed_advertising\n     * @sa non_connectable_undirected_advertising\n     */\n    struct scannable_undirected_advertising\n    {\n        /**\n         * @brief change type of advertisment\n         *\n         * If more than one advertising type is given, this function can be used\n         * to define the advertising that is used next, when the device starts\n         * advertising. If the device is currently advertising, the function\n         * has no effect until the device stops advertising and starts over to\n         * advertise.\n         *\n         * @tparam Type the next type of advertising\n         */\n        template < typename Type >\n        void change_advertising();\n\n        /** @cond HIDDEN_SYMBOLS */\n        struct meta_type :\n            details::advertising_type_meta_type,\n            details::valid_link_layer_option_meta_type {};\n\n        template < typename LinkLayer, typename Advertiser >\n        class impl : protected details::advertising_type_base\n        {\n        protected:\n\n            read_buffer fill_advertising_data()\n            {\n                using layout_t = typename pdu_layout_by_radio< typename LinkLayer::radio_t >::pdu_layout;\n\n                fill_scan_response_data();\n                const device_address& addr = link_layer().local_address();\n\n                const auto buffer = advertiser().advertising_buffer();\n\n                std::uint16_t header = adv_scan_ind_pdu_type_code;\n                std::uint8_t* body   = layout_t::body( buffer ).first;\n\n                if ( addr.is_random() )\n                    header |= header_txaddr_field;\n\n                const std::size_t size =\n                    address_length\n                  + link_layer().fill_l2cap_advertising_data( &body[ address_length ], max_advertising_data_size );\n\n                header |= size << 8;\n                adv_size_ = layout_t::data_channel_pdu_memory_size( size );\n\n                layout_t::header( buffer, header );\n                std::copy( addr.begin(), addr.end(), body );\n\n                return buffer;\n            }\n\n            read_buffer get_advertising_data()\n            {\n                return read_buffer{ advertiser().advertising_buffer().buffer, adv_size_ };\n            }\n\n            read_buffer get_scan_response_data()\n            {\n                return read_buffer{ advertiser().scan_response_buffer().buffer, adv_response_size_ };\n            }\n\n            bool is_valid_scan_request( const read_buffer& receive ) const\n            {\n                return details::advertising_type_base::is_valid_scan_request( receive, link_layer().local_address() );\n            }\n\n            bool is_valid_connect_request( const read_buffer& ) const\n            {\n                return false;\n            }\n\n        private:\n            static constexpr std::size_t    max_advertising_data_size   = 31;\n            static constexpr std::size_t    maximum_adv_send_size       = max_advertising_data_size + address_length;\n\n            void fill_scan_response_data()\n            {\n                using layout_t = typename pdu_layout_by_radio< typename LinkLayer::radio_t >::pdu_layout;\n\n                adv_response_size_ = fill_empty_scan_response_data< layout_t >(\n                    link_layer().local_address(), advertiser().scan_response_buffer() );\n            }\n\n            LinkLayer& link_layer()\n            {\n                return static_cast< LinkLayer& >( *this );\n            }\n\n            const LinkLayer& link_layer() const\n            {\n                return static_cast< const LinkLayer& >( *this );\n            }\n\n            Advertiser& advertiser()\n            {\n                return static_cast< Advertiser& >( *this );\n            }\n\n            std::size_t                     adv_size_;\n            std::size_t                     adv_response_size_;\n        };\n        /** @endcond */\n    };\n\n    /**\n     * @brief enables non-connectable undirected advertising\n     *\n     * @sa connectable_undirected_advertising\n     * @sa connectable_directed_advertising\n     * @sa scannable_undirected_advertising\n     */\n    struct non_connectable_undirected_advertising\n    {\n        /**\n         * @brief change type of advertisment\n         *\n         * If more than one advertising type is given, this function can be used\n         * to define the advertising that is used next, when the device starts\n         * advertising. If the device is currently advertising, the function\n         * has no effect until the device stops advertising and starts over to\n         * advertise.\n         *\n         * @tparam Type the next type of advertising\n         */\n        template < typename Type >\n        void change_advertising();\n\n        /** @cond HIDDEN_SYMBOLS */\n        struct meta_type :\n            details::advertising_type_meta_type,\n            details::valid_link_layer_option_meta_type {};\n\n        template < typename LinkLayer, typename Advertiser >\n        class impl : protected details::advertising_type_base\n        {\n        protected:\n            read_buffer fill_advertising_data()\n            {\n                const device_address& addr = link_layer().local_address();\n                using layout_t = typename pdu_layout_by_radio< typename LinkLayer::radio_t >::pdu_layout;\n\n                const auto buffer = advertiser().advertising_buffer();\n\n                std::uint16_t header = adv_nonconn_ind_pdu_type_code;\n                std::uint8_t* body   = layout_t::body( buffer ).first;\n\n                if ( addr.is_random() )\n                    header |= header_txaddr_field;\n\n                const std::size_t size =\n                    address_length\n                  + link_layer().fill_l2cap_advertising_data( &body[ address_length ], max_advertising_data_size );\n\n                header |= size << 8;\n\n                adv_size_ = layout_t::data_channel_pdu_memory_size( size );\n\n                layout_t::header( buffer, header );\n                std::copy( addr.begin(), addr.end(), body );\n\n                return buffer;\n            }\n\n            read_buffer get_advertising_data()\n            {\n                return advertiser().advertising_buffer();\n            }\n\n            read_buffer get_scan_response_data() const\n            {\n                return read_buffer{ nullptr, 0 };\n            }\n\n            bool is_valid_scan_request( const read_buffer& ) const\n            {\n                return false;\n            }\n\n            bool is_valid_connect_request( const read_buffer& ) const\n            {\n                return false;\n            }\n\n        private:\n            static constexpr std::size_t    max_advertising_data_size   = 31;\n\n            LinkLayer& link_layer()\n            {\n                return static_cast< LinkLayer& >( *this );\n            }\n\n            Advertiser& advertiser()\n            {\n                return static_cast< Advertiser& >( *this );\n            }\n\n            std::size_t                     adv_size_;\n        };\n        /** @endcond */\n    };\n\n    /**\n     * @brief if this options is given to the link layer, the link layer will start to\n     *        advertise automatically, when started or when disconnected.\n     *\n     * This is the default behaviour.\n     *\n     * @sa no_auto_start_advertising\n     */\n    class auto_start_advertising\n    {\n    public:\n        /** @cond HIDDEN_SYMBOLS */\n        struct meta_type :\n            details::advertising_startup_meta_type,\n            details::valid_link_layer_option_meta_type {};\n\n        template < typename Advertiser >\n        struct impl\n        {\n            bool begin_of_advertising_events() const\n            {\n                return true;\n            }\n\n            bool continued_advertising_events() const\n            {\n                return true;\n            }\n\n            void end_of_advertising_events()\n            {\n            }\n        };\n        /** @endcond */\n    };\n\n    /**\n     * @brief if this options is given to the link layer, the link layer will _not_ start to\n     *        advertise automatically, when started or when disconnected.\n     *\n     * This option will add the following functions to the link_layer:\n     * void start_advertising()\n     * void stop_advertising()\n     * bool is_advertising()\n     *\n     * @sa auto_start_advertising\n     */\n    class no_auto_start_advertising\n    {\n    public:\n        /**\n         * @brief starts to advertise.\n         *\n         * If the device is currently connected and only one connection is supported, the\n         * link layer will terminate the connection and then start to advertise.\n         */\n        void start_advertising();\n\n        /**\n         * @brief same as start_advertising(), but the link layer will automatically stop\n         *        to advertise after count advertising events.\n         */\n        void start_advertising( unsigned count );\n\n        /**\n         * @brief stop advertising\n         */\n        void stop_advertising();\n\n        /** @cond HIDDEN_SYMBOLS */\n        struct meta_type :\n            details::advertising_startup_meta_type,\n            details::valid_link_layer_option_meta_type {};\n\n        template < typename Advertiser >\n        class impl\n        {\n        public:\n            impl()\n                : started_( false )\n                , enabled_( false )\n                , count_( 0 )\n            {}\n\n            void start_advertising()\n            {\n                const bool start = !enabled_;\n\n                count_   = 0;\n                enabled_ = true;\n\n                if ( start && started_ )\n                    static_cast< Advertiser& >( *this ).handle_start_advertising();\n            }\n\n            /**\n             * @brief same as start_advertising(), but the link layer will automatically stop\n             *        to advertise after count advertising PDUs send.\n             */\n            void start_advertising( unsigned count )\n            {\n                assert( count );\n\n                const bool start = !enabled_;\n\n                count_ = count;\n                enabled_ = true;\n\n                if ( start && started_ )\n                    static_cast< Advertiser& >( *this ).handle_start_advertising();\n            }\n\n            /**\n             * @brief stop advertising\n             */\n            void stop_advertising()\n            {\n                enabled_ = false;\n                count_   = 0;\n            }\n\n        protected:\n            bool begin_of_advertising_events()\n            {\n                bool result = enabled_;\n\n                if ( count_ )\n                {\n                    --count_;\n                    if ( count_ == 0 )\n                        enabled_ = false;\n                }\n\n                started_ = true;\n                return result;\n            }\n\n            bool continued_advertising_events()\n            {\n                bool result = enabled_ && started_;\n\n                if ( count_ )\n                {\n                    --count_;\n                    if ( count_ == 0 )\n                        enabled_ = false;\n                }\n\n                return result;\n            }\n\n            void end_of_advertising_events()\n            {\n                started_ = false;\n                enabled_ = false;\n            }\n        private:\n            volatile bool       started_;\n            volatile bool       enabled_;\n            volatile unsigned   count_;\n        };\n        /** @endcond */\n    };\n\n    /**\n     * @brief advertising interval in ms in the range 20ms to 10.24s\n     */\n    template < std::uint16_t AdvertisingIntervalMilliSeconds, typename = typename details::check_advertising_interval_parameter< AdvertisingIntervalMilliSeconds >::type >\n    struct advertising_interval\n    {\n        /** @cond HIDDEN_SYMBOLS */\n        struct meta_type :\n            details::advertising_interval_meta_type,\n            details::valid_link_layer_option_meta_type {};\n        /** @endcond */\n\n        /**\n         * timeout in ms roundet to the next 0.625ms\n         */\n    protected:\n        delta_time current_advertising_interval() const\n        {\n            return delta_time( AdvertisingIntervalMilliSeconds * 1000 );\n        }\n    };\n\n    /**\n     * @brief adds the abillity to change the advertising interval\n     *\n     * Using this type as an option to the link_layer, adds the documented\n     * functions to the link_layer.\n     */\n    struct variable_advertising_interval\n    {\n    public:\n        variable_advertising_interval()\n            : interval_( delta_time::msec( 100 ) )\n        {\n        }\n\n        /**\n         * @brief sets the advertising interval in ms in the range 20ms to 10.24s\n         */\n        void advertising_interval_ms( unsigned interval_ms )\n        {\n            if ( interval_ms >= 20 and interval_ms <= 10240 )\n                interval_ = delta_time::msec( interval_ms );\n        }\n\n        /**\n         * @brief sets the advertising interval in ms in the range 20ms to 10.24s\n         */\n        void advertising_interval( delta_time interval )\n        {\n            if ( interval >= delta_time::msec( 20 ) and interval <= delta_time::msec( 10240 ) )\n                interval_ = interval;\n        }\n\n        /**\n         * @brief currently used advertising interval\n         */\n        delta_time current_advertising_interval() const\n        {\n            return interval_;\n        }\n\n        /** @cond HIDDEN_SYMBOLS */\n        struct meta_type :\n            details::advertising_interval_meta_type,\n            details::valid_link_layer_option_meta_type {};\n    private:\n        delta_time interval_;\n        /** @endcond */\n    };\n\n    namespace details {\n        struct advertising_channel_map_base {\n            static constexpr unsigned       first_advertising_channel   = 37;\n            static constexpr unsigned       last_advertising_channel    = 39;\n        };\n    }\n\n    /**\n     * @brief adds the abillity to set a channel map for advertising\n     *\n     * Using this type as an option to the link_layer, adds the documented\n     * functions to the link_layer.\n     *\n     * By default, all 3 channels are enabled. Setting the channel map to\n     * empty is not supported.\n     *\n     * It is not supported to change the channel map during advertising.\n     */\n    struct variable_advertising_channel_map : details::advertising_channel_map_base\n    {\n        /**\n         * @brief adds the given channel to the map\n         */\n        void add_channel_to_advertising_channel_map( unsigned channel )\n        {\n            assert( channel >= first_advertising_channel );\n            assert( channel <= last_advertising_channel );\n\n            channel -= first_advertising_channel;\n            map_ = map_ | ( 1 << channel );\n\n            current_channel_index_ = first_channel_index();\n        }\n\n        /**\n         * @brief removes the channel from the map.\n         *\n         * Make sure to have at least one remaining channel when starting advertising.\n         */\n        void remove_channel_from_advertsing_channel_map( unsigned channel )\n        {\n            assert( channel >= first_advertising_channel );\n            assert( channel <= last_advertising_channel );\n\n            channel -= first_advertising_channel;\n            map_ = map_ & ~( 1 << channel );\n\n            if ( map_ )\n                current_channel_index_ = first_channel_index();\n        }\n\n        /** @cond HIDDEN_SYMBOLS */\n        struct meta_type :\n            details::advertising_channel_map_meta_type,\n            details::valid_link_layer_option_meta_type {};\n    protected:\n        variable_advertising_channel_map()\n            : current_channel_index_( 0 )\n            , map_( 0x7 )\n        {}\n\n        unsigned current_channel() const\n        {\n            return current_channel_index_ + first_advertising_channel;\n        }\n\n        void next_channel()\n        {\n            assert( map_ != 0 );\n\n            ++current_channel_index_;\n\n            // seek next position in map that is set to 1\n            for ( ; ( 1u << current_channel_index_ ) == 0 && ( 1u << current_channel_index_ ) <= map_; ++current_channel_index_ )\n                ;\n\n            if ( ( 1u << current_channel_index_ ) > map_ )\n                current_channel_index_ = first_channel_index();\n        }\n\n        bool first_channel_selected() const\n        {\n            return current_channel_index_ == first_channel_index();\n        }\n\n    private:\n        unsigned first_channel_index() const\n        {\n            unsigned result = 0;\n            for ( ; ( map_ & ( 1 << result ) ) == 0; ++result )\n                ;\n\n            return result;\n        }\n\n        unsigned    current_channel_index_;\n        unsigned    map_;\n        /** @endcond */\n    };\n\n    /**\n     * @brief channel map that contains all three advertising channels\n     *\n     * This is the default behaviour\n     */\n    struct all_advertising_channel_map : details::advertising_channel_map_base\n    {\n        /** @cond HIDDEN_SYMBOLS */\n        struct meta_type :\n            details::advertising_channel_map_meta_type,\n            details::valid_link_layer_option_meta_type {};\n\n    protected:\n        all_advertising_channel_map()\n            : current_channel_index_( first_advertising_channel )\n        {}\n\n        unsigned current_channel() const\n        {\n            return current_channel_index_;\n        }\n\n        void next_channel()\n        {\n            current_channel_index_ = current_channel_index_ == last_advertising_channel\n                ? first_advertising_channel\n                : current_channel_index_ + 1;\n        }\n\n        bool first_channel_selected() const\n        {\n            return current_channel_index_ == this->first_advertising_channel;\n        }\n\n    private:\n        unsigned    current_channel_index_;\n        /** @endcond */\n    };\n\n    namespace details {\n        /*\n         * Type to implement the single and multiple adverting type advertisings\n         */\n        template < typename LinkLayer, typename Options, typename ... Advertisings >\n        class advertiser;\n\n        struct advertiser_base_base\n        {\n            static constexpr std::uint32_t  advertising_radio_access_address = 0x8E89BED6;\n            static constexpr std::uint32_t  advertising_crc_init             = 0x555555;\n        };\n\n        template < typename LinkLayer, typename ... Options >\n        class advertiser_base :\n            public advertiser_base_base,\n            public bluetoe::details::find_by_meta_type<\n                    details::advertising_interval_meta_type,\n                    Options..., advertising_interval< 100 > >::type,\n            public bluetoe::details::find_by_meta_type<\n                    details::advertising_channel_map_meta_type,\n                    Options..., all_advertising_channel_map >::type\n        {\n        public:\n            /*\n             * link layer raw_pdu_buffer() is devided into 3 sections:\n             *  - advertising_buffer()\n             *  - scan_response_buffer()\n             *  - advertising_receive_buffer()\n             */\n            read_buffer advertising_buffer()\n            {\n                using layout_t = typename pdu_layout_by_radio< typename LinkLayer::radio_t >::pdu_layout;\n\n                return read_buffer{\n                    base_link_layer().raw_pdu_buffer(),\n                    layout_t::data_channel_pdu_memory_size( advertising_type_base::max_advertising_pdu_size ) };\n            }\n\n            read_buffer scan_response_buffer()\n            {\n                using layout_t = typename pdu_layout_by_radio< typename LinkLayer::radio_t >::pdu_layout;\n\n                return read_buffer{\n                    base_link_layer().raw_pdu_buffer()\n                      + layout_t::data_channel_pdu_memory_size( advertising_type_base::max_advertising_pdu_size ),\n                    layout_t::data_channel_pdu_memory_size( advertising_type_base::max_scan_response_pdu_size ) };\n            }\n\n            read_buffer advertising_receive_buffer()\n            {\n                using layout_t = typename pdu_layout_by_radio< typename LinkLayer::radio_t >::pdu_layout;\n\n                return read_buffer{\n                    base_link_layer().raw_pdu_buffer()\n                      + layout_t::data_channel_pdu_memory_size( advertising_type_base::max_advertising_pdu_size )\n                      + layout_t::data_channel_pdu_memory_size( advertising_type_base::max_scan_response_pdu_size ),\n                    layout_t::data_channel_pdu_memory_size( advertising_type_base::maximum_adv_request_size ) };\n            }\n\n            static constexpr std::size_t maximum_required_advertising_buffer()\n            {\n                using layout_t = typename pdu_layout_by_radio< typename LinkLayer::radio_t >::pdu_layout;\n\n                return layout_t::data_channel_pdu_memory_size( advertising_type_base::max_advertising_pdu_size )\n                     + layout_t::data_channel_pdu_memory_size( advertising_type_base::max_scan_response_pdu_size )\n                     + layout_t::data_channel_pdu_memory_size( advertising_type_base::maximum_adv_request_size );\n            };\n\n        protected:\n            advertiser_base()\n                : adv_perturbation_( 0 )\n            {\n            }\n\n            delta_time next_adv_event()\n            {\n                if ( !this->first_channel_selected() )\n                    return delta_time::now();\n\n                adv_perturbation_ = ( adv_perturbation_ + 7 ) % ( max_adv_perturbation_ + 1 );\n\n                return this->current_advertising_interval() + delta_time::msec( adv_perturbation_ );\n            }\n\n            LinkLayer& base_link_layer()\n            {\n                return static_cast< LinkLayer& >( *this );\n            }\n\n        private:\n            static constexpr unsigned       max_adv_perturbation_ = 10;\n\n            unsigned                        adv_perturbation_;\n        };\n\n        template < typename LinkLayer, typename Advertising, typename ... Options >\n        struct start_stop_implementation :\n            bluetoe::details::find_by_meta_type<\n                advertising_startup_meta_type,\n                Options...,\n                auto_start_advertising\n            >::type::template impl<\n                advertiser<\n                    LinkLayer,\n                    std::tuple< Options... >,\n                    Advertising\n                >\n            > {};\n\n        /*\n         * Implementation for a single advertising type\n         */\n        template < typename LinkLayer, typename ... Options, typename Advertising >\n        class advertiser< LinkLayer, std::tuple< Options... >, std::tuple< Advertising > > :\n            public Advertising::template impl< LinkLayer, advertiser< LinkLayer, std::tuple< Options... >, std::tuple< Advertising > > >,\n            public advertiser_base< LinkLayer, Options... >,\n            public start_stop_implementation< LinkLayer, std::tuple< Advertising >, Options... >\n        {\n        public:\n\n            /*\n             * Send out, first advertising\n             */\n            void handle_start_advertising()\n            {\n                const read_buffer advertising_data = this->fill_advertising_data();\n                const read_buffer response_data    = this->get_scan_response_data();\n\n                if ( !advertising_data.empty() && this->begin_of_advertising_events() )\n                {\n                    this->base_link_layer().set_access_address_and_crc_init(\n                        this->advertising_radio_access_address,\n                        this->advertising_crc_init );\n\n                    this->base_link_layer().schedule_advertisment(\n                        this->current_channel(),\n                        write_buffer( advertising_data ),\n                        write_buffer( response_data ),\n                        delta_time::now(),\n                        this->advertising_receive_buffer() );\n                }\n            }\n\n            void handle_stop_advertising()\n            {\n                this->end_of_advertising_events();\n            }\n\n            /*\n             * handling incomming PDU\n             */\n            bool handle_adv_receive( read_buffer receive, device_address& remote_address )\n            {\n                if ( this->is_valid_connect_request( receive ) )\n                {\n                    using layout_t = typename pdu_layout_by_radio< typename LinkLayer::radio_t >::pdu_layout;\n\n                    const std::uint8_t* const body   = layout_t::body( receive ).first;\n                    const std::uint16_t       header = layout_t::header( receive );\n\n                    remote_address = device_address( &body[ 0 ], header & 0x40 );\n\n                    if ( this->base_link_layer().is_connection_request_in_filter( remote_address ) )\n                        return true;\n                }\n\n                handle_adv_timeout();\n\n                return false;\n            }\n\n            void handle_adv_timeout()\n            {\n                const read_buffer advertising_data = this->base_link_layer().l2cap_adverting_data_or_scan_response_data_changed()\n                    ? this->fill_advertising_data()\n                    : this->get_advertising_data();\n\n                const read_buffer response_data    = this->get_scan_response_data();\n\n                if ( !advertising_data.empty() && this->continued_advertising_events() )\n                {\n                    this->next_channel();\n\n                    this->base_link_layer().schedule_advertisment(\n                        this->current_channel(),\n                        write_buffer( advertising_data ),\n                        write_buffer( response_data ),\n                        this->next_adv_event(),\n                        this->advertising_receive_buffer() );\n                }\n            }\n\n        };\n\n        /*\n         * Default\n         */\n        template < typename LinkLayer, typename ... Options >\n        class advertiser< LinkLayer, std::tuple< Options... >, std::tuple<> > :\n            public advertiser< LinkLayer, std::tuple< Options... >, std::tuple< connectable_undirected_advertising > >\n        {\n        };\n\n        template < typename LinkLayer, typename Options, typename Advertiser, typename ... Types >\n        class multipl_advertiser_base;\n\n        template < typename LinkLayer, typename Options, typename Advertiser >\n        class multipl_advertiser_base< LinkLayer, Options, Advertiser >\n        {\n        protected:\n            read_buffer fill_advertising_data( unsigned )\n            {\n                return read_buffer{ nullptr, 0 };\n            }\n\n            read_buffer get_advertising_data( unsigned )\n            {\n                return read_buffer{ nullptr, 0 };\n            }\n\n            read_buffer get_scan_response_data( unsigned )\n            {\n                return read_buffer{ nullptr, 0 };\n            }\n\n            bool is_valid_scan_request( const read_buffer&, unsigned ) const\n            {\n                return false;\n            }\n\n            bool is_valid_connect_request( const read_buffer&, unsigned ) const\n            {\n                return false;\n            }\n         };\n\n        template < typename LinkLayer, typename Options, typename Advertiser, typename Type, typename ... Types >\n        class multipl_advertiser_base< LinkLayer, Options, Advertiser, Type, Types... > :\n            public Type::template impl< LinkLayer, Advertiser >,\n            public multipl_advertiser_base< LinkLayer, Options, Advertiser, Types... >\n        {\n        protected:\n\n            read_buffer fill_advertising_data( unsigned selected )\n            {\n                return selected == 0\n                    ? adv_type::fill_advertising_data()\n                    : tail_type::fill_advertising_data( selected -1 );\n            }\n\n            read_buffer get_advertising_data( unsigned selected )\n            {\n                return selected == 0\n                    ? adv_type::get_advertising_data()\n                    : tail_type::get_advertising_data( selected -1 );\n            }\n\n            read_buffer get_scan_response_data( unsigned selected )\n            {\n                return selected == 0\n                    ? adv_type::get_scan_response_data()\n                    : tail_type::get_scan_response_data( selected -1 );\n            }\n\n            bool is_valid_scan_request( const read_buffer& b, unsigned selected ) const\n            {\n                return selected == 0\n                    ? adv_type::is_valid_scan_request( b )\n                    : tail_type::is_valid_scan_request( b, selected -1 );\n            }\n\n            bool is_valid_connect_request( const read_buffer& b, unsigned selected ) const\n            {\n                return selected == 0\n                    ? adv_type::is_valid_connect_request( b )\n                    : tail_type::is_valid_connect_request( b, selected -1 );\n            }\n\n        private:\n            using adv_type  = typename Type::template impl< LinkLayer, Advertiser >;\n            using tail_type = multipl_advertiser_base< LinkLayer, Options, Advertiser, Types... >;\n        };\n\n        /*\n         * Wrapper around multiple advertising types\n         */\n        template < typename LinkLayer, typename ... Options, typename FirstAdv, typename SecondAdv, typename ... Advertisings >\n        class advertiser< LinkLayer, std::tuple< Options... >, std::tuple< FirstAdv, SecondAdv, Advertisings... > > :\n            public advertiser_base< LinkLayer, Options... >,\n            public multipl_advertiser_base<\n                LinkLayer,\n                std::tuple< Options... >,\n                advertiser< LinkLayer, std::tuple< Options... >, std::tuple< FirstAdv, SecondAdv, Advertisings... > >,\n                FirstAdv, SecondAdv, Advertisings...\n            >,\n            public start_stop_implementation< LinkLayer, std::tuple< FirstAdv, SecondAdv, Advertisings... >, Options... >\n        {\n        public:\n            advertiser()\n                : selected_( 0 )\n                , proposal_( 0 )\n            {\n            }\n\n            void handle_start_advertising()\n            {\n                selected_ = proposal_;\n                const read_buffer advertising_data = this->fill_advertising_data( selected_ );\n                const read_buffer response_data    = this->get_scan_response_data( selected_ );\n\n                if ( !advertising_data.empty() && this->begin_of_advertising_events() )\n                {\n                    this->base_link_layer().set_access_address_and_crc_init(\n                        this->advertising_radio_access_address,\n                        this->advertising_crc_init );\n\n                    this->base_link_layer().schedule_advertisment(\n                        this->current_channel(),\n                        write_buffer( advertising_data ),\n                        write_buffer( response_data ),\n                        delta_time::now(),\n                        this->advertising_receive_buffer() );\n                }\n            }\n\n            void handle_stop_advertising()\n            {\n                this->end_of_advertising_events();\n            }\n\n            bool handle_adv_receive( read_buffer receive, device_address& remote_address )\n            {\n                if ( this->is_valid_connect_request( receive, selected_ ) )\n                {\n                    using layout_t = typename pdu_layout_by_radio< typename LinkLayer::radio_t >::pdu_layout;\n\n                    const std::uint8_t* const body   = layout_t::body( receive ).first;\n                    const std::uint16_t       header = layout_t::header( receive );\n\n                    remote_address = device_address( &body[ 0 ], header & 0x40 );\n\n                    if ( this->base_link_layer().is_connection_request_in_filter( remote_address ) )\n                        return true;\n                }\n\n                handle_adv_timeout();\n\n                return false;\n            }\n\n            void handle_adv_timeout()\n            {\n                const bool fill_data = selected_ != proposal_\n                    || this->base_link_layer().l2cap_adverting_data_or_scan_response_data_changed();\n\n                selected_ = proposal_;\n                const read_buffer advertising_data = fill_data\n                    ? this->fill_advertising_data( selected_ )\n                    : this->get_advertising_data( selected_ );\n\n                const read_buffer response_data    = this->get_scan_response_data( selected_ );\n\n                if ( !advertising_data.empty() && this->continued_advertising_events() )\n                {\n                    this->next_channel();\n\n                    this->base_link_layer().schedule_advertisment(\n                        this->current_channel(),\n                        write_buffer( advertising_data ),\n                        write_buffer( response_data ),\n                        this->next_adv_event(),\n                        this->advertising_receive_buffer() );\n                }\n            }\n\n            /*\n             * this is the true implementation of all the documentated function within the advertising types\n             */\n            template < typename Type >\n            void change_advertising()\n            {\n                proposal_ = bluetoe::details::index_of< Type, FirstAdv, SecondAdv, Advertisings... >::value;\n                assert( proposal_ != sizeof...(Advertisings) + 2 );\n            }\n\n        private:\n\n            unsigned selected_;\n            unsigned proposal_;\n        };\n\n        /** @cond HIDDEN_SYMBOLS */\n        template < typename LinkLayer, typename ... Options >\n        using select_advertiser_implementation =\n            advertiser<\n                LinkLayer,\n                std::tuple< Options... >,\n                typename bluetoe::details::find_all_by_meta_type< advertising_type_meta_type,\n                    Options... >::type >;\n        /** @endcond */\n    }\n}\n}\n#endif\n"
  },
  {
    "path": "bluetoe/link_layer/include/bluetoe/buffer.hpp",
    "content": "#ifndef BLUETOE_LINK_LAYER_BUFFER_HPP\n#define BLUETOE_LINK_LAYER_BUFFER_HPP\n\n#include <cstdlib>\n#include <cstdint>\n#include <cassert>\n#include <initializer_list>\n#include <algorithm>\n\nnamespace bluetoe {\nnamespace link_layer {\n\n    /**\n     * @brief type suitable to store the location and size of a chunk of\n     *        memory that can be used to receive from the radio\n     */\n    struct read_buffer\n    {\n        /**\n         * Points to the location where content of the buffer is located.\n         * If size is 0, the value is unspecified.\n         * The allignment of the address is unspecified.\n         */\n        std::uint8_t*   buffer;\n\n        /**\n         * Size of the chunk. If size is 0, an empty buffer is indicated and the value of buffer\n         * is unspecified\n         */\n        std::size_t     size;\n\n        /**\n         * @brief returns true, if the buffer is empty\n         */\n        bool empty() const\n        {\n            return buffer == nullptr && size == 0;\n        }\n\n        /**\n         * @brief copies the given data into the buffer\n         * @pre data.size() <= size\n         */\n        void fill( std::initializer_list< std::uint8_t > data )\n        {\n            assert( data.size() <= size );\n            std::copy( data.begin(), data.end(), buffer );\n        }\n    };\n\n    /**\n     * @brief fills the given buffer with the given data.\n     *\n     * The first two bytes of data are copied into the header of the buffer using the specified Layout.\n     * The remaining part of data is copied into the body of the buffer using the specified Layout.\n     *\n     * @sa read_buffer\n     * @sa default_pdu_layout\n     */\n    template < class Layout >\n    void fill( const read_buffer& buffer, std::initializer_list< std::uint8_t > data )\n    {\n        if ( data.size() >= 1 )\n        {\n            std::uint16_t header = *data.begin();\n\n            if ( data.size() >= 2 )\n                header |= *std::next( data.begin() ) << 8;\n\n            Layout::header( buffer, header );\n\n            if ( data.size() >= 3 )\n            {\n                std::uint8_t* body = Layout::body( buffer ).first;\n                std::copy( std::next( data.begin(), 2 ), std::end( data ), body );\n            }\n        }\n    }\n\n    /**\n     * @brief type suitable to store the location and size of a chunk of\n     *        memory that can be used to transmit to the radio\n     */\n    struct write_buffer\n    {\n        /** @copydoc read_buffer::buffer */\n        const std::uint8_t* buffer;\n\n        /** @copydoc read_buffer::size */\n        std::size_t         size;\n\n        /**\n         * @brief returns true, if the buffer is empty\n         */\n        bool empty() const\n        {\n            return buffer == nullptr && size == 0;\n        }\n\n        /**\n         * @brief constructs a ready-only buffer from a writable buffer\n         */\n        explicit write_buffer( const read_buffer& rhs )\n            : buffer( rhs.buffer )\n            , size( rhs.size )\n        {}\n\n        /**\n         * @brief constructs an empty buffer\n         */\n        write_buffer()\n            : buffer( nullptr )\n            , size( 0 )\n        {\n        }\n\n        /**\n         * @brief constructs a buffer pointing to the given location, with the given size\n         */\n        write_buffer( const std::uint8_t* b, std::size_t s )\n            : buffer( b )\n            , size( s )\n        {\n        }\n    };\n}\n}\n\n#endif\n"
  },
  {
    "path": "bluetoe/link_layer/include/bluetoe/channel_map.hpp",
    "content": "#ifndef BLUETOE_LINK_LAYER_CHANNEL_MAP_HPP\n#define BLUETOE_LINK_LAYER_CHANNEL_MAP_HPP\n\n#include <cstdint>\n\nnamespace bluetoe {\nnamespace link_layer {\n\n    /**\n     * @brief map that keeps track of the list of used channels and calculates the next channel based on the last used channel\n     */\n    class channel_map\n    {\n    public:\n        channel_map();\n\n        /**\n         * @brief sets a new list of used channels and a new hop value.\n         *\n         * The function returns true, if the given parameters are valid.\n         * A valid map contains at least 2 channel.\n         * A hop increment shall have a value in the range of 5 to 16.\n         */\n        bool reset( const std::uint8_t* map, const unsigned hop );\n\n        /**\n         * @brief sets a new list of used channels and keeps the old hop value.\n         *\n         * @pre reset( const std::uint8_t* map, const unsigned hop ) must have been called before, to have an old hop value\n         */\n        bool reset( const std::uint8_t* map );\n\n        /**\n         * the BLE channel hop sequence is 37 entries long, after 37 hops, the sequence starts again.\n         * This function returns the entries in this sequence. The channel for the first entry is given\n         * by calling the function with index = 0, the last entry with index = max_number_of_data_channels -1\n         */\n        unsigned data_channel( unsigned index ) const;\n\n        /**\n         * the number of channels, used as data channel.\n         */\n        static constexpr unsigned max_number_of_data_channels = 37;\n    private:\n        unsigned build_used_channel_map( const std::uint8_t* map, std::uint8_t* used ) const;\n\n        std::uint8_t map_[ max_number_of_data_channels ];\n        std::uint8_t hop_;\n    };\n}\n}\n#endif // include guard\n"
  },
  {
    "path": "bluetoe/link_layer/include/bluetoe/connection_callbacks.hpp",
    "content": "#ifndef BLUETOE_LINK_LAYER_CONNECTION_CALLBACKS_HPP\n#define BLUETOE_LINK_LAYER_CONNECTION_CALLBACKS_HPP\n\n#include <bluetoe/meta_types.hpp>\n#include <bluetoe/ring.hpp>\n\nnamespace bluetoe {\nnamespace link_layer {\n    class connection_details;\n\n    namespace details {\n        struct connection_callbacks_meta_type {};\n    }\n\n    /**\n     * @brief provides a type and an instance to call connection related callbacks on.\n     *\n     * The parameter T have to be a class type with following optional none static member\n     * functions:\n     *\n     * template < typename ConnectionData >\n     * void ll_connection_requested(\n     *          const bluetoe::link_layer::connection_details&   details,\n     *          const bluetoe::link_layer::connection_addresses& addresses,\n     *                ConnectionData&                            connection );\n     *\n     * template < typename ConnectionData >\n     * void ll_connection_attempt_timeout(\n     *                ConnectionData&                            connection );\n     *\n     * template < typename ConnectionData >\n     * void ll_connection_established(\n     *          const bluetoe::link_layer::connection_details&   details,\n     *          const bluetoe::link_layer::connection_addresses& addresses,\n     *                ConnectionData&                            connection );\n     *\n     * template < typename ConnectionData >\n     * void ll_connection_changed(\n     *          const bluetoe::link_layer::connection_details&  details,\n     *                ConnectionData&                           connection );\n     *\n     * template < typename ConnectionData >\n     * void ll_connection_closed( std::uint8_t reason, ConnectionData& connection );\n     *\n     * template < typename ConnectionData >\n     * void ll_version( std::uint8_t version, std::uint16_t company, std::uint16_t subversion, const ConnectionData& connection );\n     *\n     * template < typename ConnectionData >\n     * void ll_rejected( std::uint8_t error_code, const ConnectionData& connection );\n     *\n     * template < typename ConnectionData >\n     * void ll_unknown( std::uint8_t unknown_type, const ConnectionData& connection );\n     *\n     * template < typename ConnectionData >\n     * void ll_remote_features( std::uint8_t remote_features[ 8 ], const ConnectionData& connection );\n     *\n     * template < typename ConnectionData >\n     * void ll_phy_updated(\n     *  bluetoe::link_layer::phy_ll_encoding::phy_ll_encoding_t transmit_encoding,\n     *  bluetoe::link_layer::phy_ll_encoding::phy_ll_encoding_t receive_encoding,\n     *  const ConnectionData& connection );\n     *\n     * ll_connection_requested() will be called, as soon, as a connection request is received.\n     * ll_connection_established() is called, after the first connection event actually toke place.\n     *\n     * ll_connection_attempt_timeout() will be called, when the connection was reported as beeing requested\n     * (ll_connection_requested()) but not established (ll_connection_established()) and then timed out, because\n     * not a single connection event happend.\n     */\n    template < typename T, T& Obj >\n    struct connection_callbacks {\n        /** @cond HIDDEN_SYMBOLS */\n        struct meta_type :\n            details::connection_callbacks_meta_type,\n            details::valid_link_layer_option_meta_type {};\n\n        void connection_request( const connection_addresses& addresses )\n        {\n            addresses_  = addresses;\n        }\n\n        template < class Connection, class Radio >\n        void connection_requested(\n            const connection_details&   details,\n            Connection&                 connection,\n            Radio&                      r )\n        {\n            const event_data data( requested, &connection, details );\n            events_.try_push( data );\n\n            r.wake_up();\n        }\n\n        // this functions are called from the interrupt handlers of the scheduled radio and just store the informations that\n        // are provided.\n        template < class Connection, class Radio >\n        void connection_established(\n            const connection_details&   details,\n            Connection&                 connection,\n            Radio&                      r )\n        {\n            const event_data data( established, &connection, details );\n            events_.try_push( data );\n\n            r.wake_up();\n        }\n\n        template < class Connection, class Radio >\n        void connection_attempt_timeout( Connection& connection, Radio& r )\n        {\n            const event_data data( attempt_timeout, &connection );\n            events_.try_push( data );\n\n            r.wake_up();\n        }\n\n        template < class Connection, class Radio >\n        void connection_changed( const bluetoe::link_layer::connection_details& details, Connection& connection, Radio& r )\n        {\n            const event_data data = { changed, &connection, details };\n            events_.try_push( data );\n\n            r.wake_up();\n        }\n\n        template < class Connection, class Radio >\n        void connection_closed( std::uint8_t reason, Connection& connection, Radio& r )\n        {\n            event_data data = { closed, &connection };\n            data.raw_details_[ 0 ] = reason;\n            events_.try_push( data );\n\n            r.wake_up();\n        }\n\n        template < class Connection, class Radio >\n        void procedure_rejected( std::uint8_t error_code, Connection& connection, Radio& r )\n        {\n            event_data data = { rejected, &connection };\n            data.raw_details_[ 0 ] = error_code;\n            events_.try_push( data );\n\n            r.wake_up();\n        }\n\n        template < class Connection, class Radio >\n        void procedure_unknown( std::uint8_t error_code, Connection& connection, Radio& r )\n        {\n            event_data data = { unknown, &connection };\n            data.raw_details_[ 0 ] = error_code;\n            events_.try_push( data );\n\n            r.wake_up();\n        }\n\n        template < class Connection, class Radio >\n        void version_indication_received( const std::uint8_t* details, Connection& connection, Radio& r )\n        {\n            event_data data = { version, &connection };\n            std::copy( details, details + version_ind_size, &data.raw_details_[ 0 ] );\n            events_.try_push( data );\n\n            r.wake_up();\n        }\n\n        template < class Connection, class Radio >\n        void remote_features_received( const std::uint8_t rf[ 8 ], Connection& connection, Radio& r )\n        {\n            event_data data = { remote_features, &connection };\n            std::copy( rf, rf + feature_field_size, &data.raw_details_[ 0 ] );\n            events_.try_push( data );\n\n            r.wake_up();\n        }\n\n        template < class Connection, class Radio >\n        void phy_update( std::uint8_t phy_c_to_p, std::uint8_t phy_p_to_c, Connection& connection, Radio& r )\n        {\n            event_data data = { update_phy, &connection };\n            data.raw_details_[ 0 ] = phy_c_to_p;\n            data.raw_details_[ 1 ] = phy_p_to_c;\n            events_.try_push( data );\n\n            r.wake_up();\n        }\n\n        template < class LinkLayer >\n        void handle_connection_events() {\n            event_data data;\n\n            while ( events_.try_pop( data ) )\n            {\n                if ( data.event_type_ == requested )\n                {\n                    call_ll_connection_requested< T >( Obj, data.details_, addresses_, connection_data< LinkLayer >( data ) );\n                }\n                else if ( data.event_type_ == attempt_timeout )\n                {\n                    call_ll_connection_attempt_timeout< T >( Obj, connection_data< LinkLayer >( data ) );\n                }\n                else if ( data.event_type_ == established )\n                {\n                    call_ll_connection_established< T >( Obj, data.details_, addresses_, connection_data< LinkLayer >( data ) );\n                }\n                else if ( data.event_type_ == changed )\n                {\n                    call_ll_connection_changed< T >( Obj, data.details_, connection_data< LinkLayer >( data ) );\n                }\n                else if ( data.event_type_ == closed )\n                {\n                    call_ll_connection_closed< T >( Obj, data.raw_details_[ 0 ], connection_data< LinkLayer >( data ) );\n                }\n                else if ( data.event_type_ == version )\n                {\n                    call_ll_version< T >( Obj,\n                        connection_data< LinkLayer >( data ),\n                        data.raw_details_[ 0 ],\n                        bluetoe::details::read_16bit( &data.raw_details_[ 1 ] ),\n                        bluetoe::details::read_16bit( &data.raw_details_[ 3 ] ) );\n                }\n                else if ( data.event_type_ == rejected )\n                {\n                    call_ll_rejected< T >( Obj, connection_data< LinkLayer >( data ), data.raw_details_[ 0 ] );\n                }\n                else if ( data.event_type_ == unknown )\n                {\n                    call_ll_unknown< T >( Obj, connection_data< LinkLayer >( data ), data.raw_details_[ 0 ] );\n                }\n                else if ( data.event_type_ == remote_features )\n                {\n                    call_ll_remote_features< T >( Obj, connection_data< LinkLayer >( data ), data.raw_details_ );\n                }\n                else if ( data.event_type_ == update_phy )\n                {\n                    call_ll_phy_updated< T >( Obj, connection_data< LinkLayer >( data ),\n                        static_cast< bluetoe::link_layer::phy_ll_encoding::phy_ll_encoding_t >( data.raw_details_[ 0 ] ),\n                        static_cast< bluetoe::link_layer::phy_ll_encoding::phy_ll_encoding_t >( data.raw_details_[ 1 ] ) );\n                }\n            }\n        }\n\n    private:\n        enum event_type_t {\n            none,\n            requested,\n            attempt_timeout,\n            established,\n            changed,\n            closed,\n            version,\n            rejected,\n            unknown,\n            remote_features,\n            update_phy\n        };\n\n        static constexpr std::size_t version_ind_size = 5u;\n        static constexpr std::size_t feature_field_size = 8u;\n        static constexpr std::size_t max_events = 4u;\n\n        struct event_data {\n            event_type_t            event_type_;\n            void*                   connection_;\n            connection_details      details_;\n            std::uint8_t raw_details_[ feature_field_size ];\n\n            event_data( event_type_t ev, void* con, connection_details d = connection_details() )\n                : event_type_( ev )\n                , connection_( con )\n                , details_( d )\n            {}\n\n            event_data() {}\n        };\n\n        connection_addresses addresses_;\n        bluetoe::details::ring< max_events, event_data > events_;\n\n        template < typename LinkLayer >\n        typename LinkLayer::connection_data_t& connection_data( const event_data& d )\n        {\n            return *static_cast< typename LinkLayer::connection_data_t* >( d.connection_ );\n        }\n\n        template < typename TT, typename Connection >\n        auto call_ll_connection_requested(\n            TT&                                     obj,\n            const connection_details&               details,\n            const connection_addresses&             addr,\n            Connection&                             connection )\n                -> decltype(&TT::template ll_connection_requested< Connection >)\n        {\n            obj.ll_connection_requested( details, addr, connection );\n\n            return nullptr;\n        }\n\n        template < typename TT, typename Connection >\n        auto call_ll_connection_attempt_timeout( TT& obj, Connection& connection  )\n            -> decltype(&TT::template ll_connection_attempt_timeout< Connection >)\n        {\n            obj.ll_connection_attempt_timeout( connection );\n\n            return nullptr;\n        }\n\n        template < typename TT, typename Connection >\n        auto call_ll_connection_established(\n            TT&                                     obj,\n            const connection_details&               details,\n            const connection_addresses&             addr,\n            Connection&                             connection )\n                -> decltype(&TT::template ll_connection_established< Connection >)\n        {\n            obj.ll_connection_established( details, addr, connection );\n\n            return nullptr;\n        }\n\n        template < typename TT, typename Connection >\n        auto call_ll_connection_changed( TT& obj, const bluetoe::link_layer::connection_details& details, Connection& connection )\n            -> decltype(&TT::template ll_connection_changed< Connection >)\n        {\n            obj.ll_connection_changed( details, connection );\n\n            return nullptr;\n        }\n\n        template < typename TT, typename Connection >\n        auto call_ll_connection_closed( TT& obj, std::uint8_t reason, Connection& connection )\n            -> decltype(&TT::template ll_connection_closed< Connection >)\n        {\n            obj.ll_connection_closed( reason, connection );\n\n            return nullptr;\n        }\n\n        template < typename TT, typename Connection >\n        auto call_ll_version( TT& obj, Connection& connection, std::uint8_t version, std::uint16_t company, std::uint16_t subversion )\n            -> decltype(&TT::template ll_version< Connection >)\n        {\n            obj.ll_version(\n                version,\n                company,\n                subversion,\n                connection );\n\n            return nullptr;\n        }\n\n        template < typename TT, typename Connection >\n        auto call_ll_rejected( TT& obj, Connection& connection, std::uint8_t error_code )\n            -> decltype(&TT::template ll_rejected< Connection >)\n        {\n            obj.ll_rejected(\n                error_code,\n                connection );\n\n            return nullptr;\n        }\n\n        template < typename TT, typename Connection >\n        auto call_ll_unknown( TT& obj, Connection& connection, std::uint8_t error_code )\n            -> decltype(&TT::template ll_unknown< Connection >)\n        {\n            obj.ll_unknown(\n                error_code,\n                connection );\n\n            return nullptr;\n        }\n\n        template < typename TT, typename Connection >\n        auto call_ll_remote_features( TT& obj, Connection& connection, std::uint8_t remote_features[ 8 ] )\n            -> decltype(&TT::template ll_remote_features< Connection >)\n        {\n            obj.ll_remote_features(\n                remote_features,\n                connection );\n\n            return nullptr;\n        }\n\n        template < typename TT, typename Connection >\n        auto call_ll_phy_updated( TT& obj, Connection& connection,\n            bluetoe::link_layer::phy_ll_encoding::phy_ll_encoding_t transmit_encoding,\n            bluetoe::link_layer::phy_ll_encoding::phy_ll_encoding_t receive_encoding )\n            -> decltype(&TT::template ll_phy_updated< Connection >)\n        {\n            obj.ll_phy_updated(\n                transmit_encoding,\n                receive_encoding,\n                connection );\n\n            return nullptr;\n        }\n\n        template < typename TT >\n        void call_ll_connection_requested( ... )\n        {\n        }\n\n        template < typename TT >\n        void call_ll_connection_attempt_timeout( ... )\n        {\n        }\n\n        template < typename TT >\n        void call_ll_connection_established( ... )\n        {\n        }\n\n        template < typename TT >\n        void call_ll_connection_changed( ... )\n        {\n        }\n\n        template < typename TT >\n        void call_ll_connection_closed( ... )\n        {\n        }\n\n        template < typename TT >\n        void call_ll_version( ... )\n        {\n        }\n\n        template < typename TT >\n        void call_ll_rejected( ... )\n        {\n        }\n\n        template < typename TT >\n        void call_ll_unknown( ... )\n        {\n        }\n\n        template < typename TT >\n        void call_ll_remote_features( ... )\n        {\n        }\n\n        template < typename TT >\n        void call_ll_phy_updated( ... )\n        {\n        }\n\n        /** @endcond */\n    };\n\n    namespace details {\n        struct no_connection_callbacks {\n            struct meta_type :\n                details::connection_callbacks_meta_type,\n                details::valid_link_layer_option_meta_type {};\n\n            void connection_request( const connection_addresses& ) {}\n\n            template < class Connection, class Radio >\n            void connection_requested(\n                const connection_details&,\n                Connection&,\n                Radio& ) {}\n\n            template < class Connection, class Radio >\n            void connection_attempt_timeout( Connection&, Radio& ) {}\n\n            template < class Connection, class Radio >\n            void connection_established(\n                const connection_details&,\n                Connection&,\n                Radio& ) {}\n\n            template < class Connection, class Radio >\n            void connection_changed( const bluetoe::link_layer::connection_details&, Connection&, Radio& ) {}\n\n            template < class Connection, class Radio >\n            void connection_closed( std::uint8_t, Connection&, Radio& ) {}\n\n            template < class LinkLayer >\n            void handle_connection_events() {}\n\n            template < class Connection, class Radio >\n            void version_indication_received( const std::uint8_t*, Connection&, Radio& ) {}\n\n            template < class Connection, class Radio >\n            void procedure_rejected( std::uint8_t, Connection&, Radio& ) {}\n\n            template < class Connection, class Radio >\n            void procedure_unknown( std::uint8_t, Connection&, Radio& ) {}\n\n            template < class Connection, class Radio >\n            void remote_features_received( const std::uint8_t[8], Connection&, Radio& ) {}\n\n            template < class Connection, class Radio >\n            void phy_update( std::uint8_t, std::uint8_t, Connection&, Radio& ) {}\n\n        };\n    }\n\n}\n}\n\n#endif\n"
  },
  {
    "path": "bluetoe/link_layer/include/bluetoe/connection_details.hpp",
    "content": "#ifndef BLUETOE_LINK_LAYER_CONNECTION_DETAILS_HPP\n#define BLUETOE_LINK_LAYER_CONNECTION_DETAILS_HPP\n\n#include <bluetoe/address.hpp>\n#include <bluetoe/channel_map.hpp>\n#include <cstdint>\n\nnamespace bluetoe {\nnamespace link_layer {\n\n    /**\n     * @brief data type to store details of an established link layer connection\n     */\n    class connection_details\n    {\n    public:\n        /**\n         * @brief default c'tor leaving all data members in a meaningless state\n         */\n        connection_details() = default;\n\n        /**\n         * @brief construct the data object from its required parts.\n         */\n        connection_details(\n            const channel_map& channels,\n            std::uint16_t inter, std::uint16_t lat, std::uint16_t to,\n            unsigned acc );\n\n        /**\n         * @brief channels that a currently in use\n         */\n        const channel_map& channels() const;\n\n        /**\n         * @brief connection interval\n         *\n         * The connection interval of the current connection in units of 1.25ms.\n         */\n        std::uint16_t interval() const;\n\n        /**\n         * @brief peripheral latency\n         *\n         * The peripheral defined the number of connection events, the peripheral can\n         * skip (do not respond).\n         */\n        std::uint16_t latency() const;\n\n        /**\n         * @brief connection timeout\n         *\n         * The connection timeout of the current connection in units of 10ms.\n         */\n        std::uint16_t timeout() const;\n\n        /**\n         * @brief the cumulated sleep clock accuracy in parts per million.\n         *\n         * The cumulated sleep clock accuracy is the sum of the central's and\n         * peripheral's accuracy (clock error) and is taken into account for this\n         * connection.\n         */\n        unsigned cumulated_sleep_clock_accuracy_ppm() const;\n\n    private:\n        channel_map     channels_;\n\n        std::uint16_t   interval_;\n        std::uint16_t   latency_;\n        std::uint16_t   timeout_;\n        unsigned        accuracy_;\n    };\n\n    /**\n     * @brief local and remote address of a connection\n     */\n    class connection_addresses\n    {\n    public:\n        connection_addresses() = default;\n\n        /**\n         * @brief construct a connection addresses from a pair of device addresses\n         */\n        connection_addresses( const device_address& local, const device_address& remote );\n\n        /**\n         * @brief remote device address\n         *\n         * The remote device address of the given connection.\n         */\n        const device_address& remote_address() const;\n\n        /**\n         * @brief local device address\n         *\n         * The local device address of the given connection.\n         */\n        const device_address& local_address() const;\n\n    private:\n        device_address  local_addr_;\n        device_address  remote_addr_;\n    };\n}\n}\n\n#endif\n\n"
  },
  {
    "path": "bluetoe/link_layer/include/bluetoe/connection_event_callback.hpp",
    "content": "#ifndef BLUETOE_LINK_LAYER_CONNECTION_EVENT_CALLBACK_HPP\n#define BLUETOE_LINK_LAYER_CONNECTION_EVENT_CALLBACK_HPP\n\n#include <bluetoe/ll_meta_types.hpp>\n#include <bluetoe/delta_time.hpp>\n\nnamespace bluetoe {\nnamespace link_layer {\n\n    namespace details {\n        struct connection_event_callback_meta_type : details::valid_link_layer_option_meta_type {};\n        struct synchronized_connection_event_callback_meta_type : details::valid_link_layer_option_meta_type {};\n        struct check_synchronized_connection_event_callback_meta_type : details::valid_link_layer_option_meta_type {};\n\n        struct default_connection_event_callback\n        {\n            static void call_connection_event_callback( const delta_time& )\n            {\n            }\n\n            typedef connection_event_callback_meta_type meta_type;\n        };\n    }\n\n    /**\n     * @brief install a callback that will be called, when a connection event happened.\n     *\n     * The intended use for this feature are cases, where the CPU is switched off and even the high priority\n     * ISR of the scheduled radio will not be served.\n     *\n     * The parameter T have to be a class type with following none static member function:\n     *\n     * void ll_connection_event_happend();\n     *\n     * The template parameter RequiredTimeMS defines the minimum time available until the next connection event will\n     * happen. The callback is only called, if the given time is available. If the parameter is 0, the callback will\n     * be called on every connection event. The link layer will not use peripheral latency to increase the time between two\n     * connection events to reach the RequiredTimeMS.\n     */\n    template < typename T, T& Obj, unsigned RequiredTimeMS = 0 >\n    struct connection_event_callback\n    {\n        /** @cond HIDDEN_SYMBOLS */\n        static void call_connection_event_callback( const delta_time& time_till_next_event )\n        {\n            if ( RequiredTimeMS == 0 || time_till_next_event >= delta_time::msec( RequiredTimeMS ) )\n                Obj.ll_connection_event_happend();\n        }\n\n        typedef details::connection_event_callback_meta_type meta_type;\n        /** @endcond */\n    };\n\n    /**\n     * @brief Install a callback that will be called with a maximum period synchronized\n     *        to the connection events of established connections.\n     *\n     * @tparam T has to be of class type and fulfil this set of requirements:\n     *\n     * - A public, default constructible type `connection`\n     * - A public, none static member function:\n     *\n     *   unsigned ll_synchronized_callback( unsigned instant, connection& )\n     *\n     * - Optional, T contains the following public, none static member functions:\n     *\n     *   connection ll_synchronized_callback_connect(\n     *                  bluetoe::link_layer::delta_time connection_interval,\n     *                  unsigned                        calls_per_interval )\n     *\n     *   void ll_synchronized_callback_period_update(\n     *                  bluetoe::link_layer::delta_time connection_interval,\n     *                  unsigned                        calls_per_interval,\n     *                  connection& )\n     *\n     *   void ll_synchronized_callback_disconnect( connection& )\n     *\n     * @tparam Obj A reference to an instance of T on which the specified functions will be called.\n     *\n     * @tparam MaximumPeriodUS The maximum period at which the callback shall be called, given in µs.\n     *\n     *         If MaximumPeriodUS is larger than the connections interval, the callback will be called\n     *         with a period that is the greatest multiple of the connection interval, that is smaller\n     *         than the connections interval.\n     *\n     *         If MaximumPeriodUS is smaller than the current connections\n     *         interval, the callback will be called multiple times with a fixed period. The period is\n     *         chosen to be smaller than or equal to the given MaximumPeriodUS and so that a whole number\n     *         of calls fit into the connection interval.\n     *\n     *         Example: Connection Interval = 22.5ms, MaximumPeriodUS = 4ms\n     *                      => Effective Period = 3.75ms (callback will be call 6 times)\n     *\n     *         Example: Connection Interval = 22.5ms, MaximumPeriodUS = 60ms\n     *                      => Effective Period = 45ms (callback will be call every second connection event)\n\n     *         If the connections interval changes, the period at which the callback is called also\n     *         changes. The callback will be called irrespectively of the connection event. Even when the\n     *         connect event times out or is planned to not happen, due to peripheral latency applied.\n     *\n     * @tparam PhaseShiftUS The offset to the connection anchor in µs. A positive value denotes that\n     *         the call has to be called PhaseShiftUS µs after the anchor. Note, that in this case,\n     *         high priority CPU processing near the connection event might interrupt the given callback\n     *         invocation. A negative value denotes a call to the callback prior to the connection anchor\n     *         by the given number of µs.\n     *\n     * @tparam MaximumExecutionTimeUS The estimated, maximum execution time of the callback. This helps\n     *         the library to make sure, that the callback invocation in front of the connection event\n     *         will return, before the connection event happens. If the hardware abstraction provides\n     *         information about a minimum setup time, the library take that also into account.\n     *\n     *         If PhaseShiftUS is negative, a compile time check tests that the execution of the callback\n     *         will not run into the setup of the connection event.\n     *\n     * Once a new connection is established, Obj.ll_synchronized_callback_connect() is called (if given)\n     * with the connection interval and the number of times, the callback will be called during one interval.\n     * ll_synchronized_callback_connect() have to return the initial value of `connection`.\n     *\n     * If the connection is closed, Obj.ll_synchronized_callback_disconnect() is called with the instance of\n     * `connection` that was created by ll_synchronized_callback_connect(). If T does not provide\n     * ll_synchronized_callback_connect(), a `connection` is default constructed.\n     *\n     * If the connection interval changes, Obj.ll_synchronized_callback_period_update() is called (if given)\n     * with the connection interval and the number of times, the callback will be called during one interval.\n     *\n     * ll_synchronized_callback() will be call with the first parameter being 0 for the first invocation\n     * after the connection event and then with increased values until the value calls_per_interval - 1\n     * is reached (calls_per_interval can be obtained by having ll_synchronized_callback_connect() and\n     * ll_synchronized_callback_period_update() defined). The return value of ll_synchronized_callback()\n     * denotes the number of times, the invocation of the callback should be omitted. For example, when\n     * ll_synchronized_callback() returns 2, two planned callback invocations are omitted until the callback\n     * is called again.\n     *\n     * If the anchor is going to move due to a planned connection update procedure, there is danger\n     * of overlapping calls to the callback due to the uncertainty given by the range of transmission\n     * window size and offset. In this case, the last callback call before the instant of the update will\n     * be omitted. And the next time, the callback will be called, is after the first connection event\n     * with updated connection parameters toke place.\n     *\n     * @note This feature requires support by the hardware abstraction and thus might not be available\n     * on all platforms.\n     *\n     * @note due to connection parameter updates, there is no guaranty, that the callback will be\n     *       called with the requested MaximumPeriodUS.\n     *\n     * @note All callbacks will be called from the very same execution context (thus there is no need\n     * for synchronization between calls). The context is defined by the hardware and unspecified.\n     */\n    template < typename T, T& Obj, unsigned MaximumPeriodUS, int PhaseShiftUS, unsigned MaximumExecutionTimeUS = 100 >\n    struct synchronized_connection_event_callback\n    {\n        /**\n         * @brief stop the call of the synchronized callbacks.\n         */\n        void stop_synchronized_connection_event_callbacks();\n\n        /**\n         * @brief restart the invocation of synchronized callbacks, after they where stopped.\n         *\n         * @pre stop_synchronized_connection_event_callbacks()\n         */\n        void restart_synchronized_connection_event_callbacks();\n\n        /**\n         * @brief Ask Bluetoe to ignore the last return value of ll_synchronized_callback() and call the\n         *        callback at the next possible time.\n         */\n        void force_synchronized_connection_event_callback();\n\n        /** @cond HIDDEN_SYMBOLS */\n        template < typename LinkLayer >\n        struct impl {\n            impl()\n                : stopped_( false )\n                , force_( false )\n            {\n                static_assert( LinkLayer::hardware_supports_synchronized_user_timer, \"choosen binding does not support the use of user timer!\" );\n            }\n\n            void stop_synchronized_connection_event_callbacks()\n            {\n                stopped_ = true;\n                force_   = false;\n\n                link_layer().cancel_synchronized_user_timer();\n            }\n\n            void restart_synchronized_connection_event_callbacks()\n            {\n                instance_         = 0;\n                latency_          = 0;\n                num_intervals_since_anchor_moved_ = 0;\n\n                stopped_ = false;\n                link_layer().restart_user_timer();\n            }\n\n            void force_synchronized_connection_event_callback()\n            {\n                force_ = true;\n            }\n\n            void synchronized_connection_event_callback_new_connection( delta_time connection_interval )\n            {\n                if ( stopped_ )\n                    return;\n\n                connection_value_ = typename T::connection();\n                instance_         = PhaseShiftUS > 0 ? 1 : 0;\n                latency_          = 0;\n\n                calculate_effective_period( connection_interval );\n                call_ll_connect< T >( connection_interval, connection_value_ );\n                link_layer().cancel_synchronized_user_timer();\n                setup_timer( first_timeout() );\n            }\n\n            void synchronized_connection_event_callback_start_changing_connection()\n            {\n                link_layer().cancel_synchronized_user_timer();\n            }\n\n            void synchronized_connection_event_callback_connection_changed( delta_time connection_interval )\n            {\n                if ( stopped_ )\n                    return;\n\n                instance_         = PhaseShiftUS > 0 ? 1 : 0;\n                latency_          = 0;\n\n                calculate_effective_period( connection_interval );\n                call_ll_update< T >( connection_interval );\n                setup_timer( first_timeout() );\n            }\n\n            void synchronized_connection_event_callback_disconnect()\n            {\n                call_ll_disconnect< T >( 0 );\n                link_layer().cancel_synchronized_user_timer();\n            }\n\n            void synchronized_connection_event_callback_timeout( bool anchor_moved )\n            {\n                if ( stopped_ )\n                    return;\n\n                if ( force_ )\n                {\n                    force_   = false;\n                    latency_ = 0;\n                }\n\n                latency_ = latency_ == 0\n                    ? Obj.ll_synchronized_callback( instance_, connection_value_ )\n                    : latency_ - 1;\n\n                if ( num_calls_ )\n                    instance_ = ( instance_ + 1 ) % num_calls_;\n\n                // if the PhaseShiftUS is negative, the first callback is already first_timeout()\n                // away from the anchor\n                static constexpr unsigned first_interval_after_anchor = ( PhaseShiftUS < 0 )\n                    ? 1\n                    : 0;\n\n                num_intervals_since_anchor_moved_ = anchor_moved\n                    ? first_interval_after_anchor\n                    : num_intervals_since_anchor_moved_ + 1;\n\n                setup_timer( first_timeout() + num_intervals_since_anchor_moved_ * effective_period_ );\n            }\n\n        private:\n            template < class TT >\n            auto call_ll_connect( bluetoe::link_layer::delta_time connection_interval, typename TT::connection& con )\n                -> decltype(&TT::ll_synchronized_callback_connect)\n            {\n                con = Obj.ll_synchronized_callback_connect( connection_interval, num_calls_ );\n\n                return 0;\n            }\n\n            template < class TT >\n            void call_ll_connect( ... )\n            {\n            }\n\n            template < class TT >\n            auto call_ll_disconnect( int ) -> decltype(&TT::ll_synchronized_callback_disconnect)\n            {\n                Obj.ll_synchronized_callback_disconnect( connection_value_ );\n                return 0;\n            }\n\n            template < class TT >\n            void call_ll_disconnect( ... )\n            {\n            }\n\n            template < class TT >\n            auto call_ll_update(\n                bluetoe::link_layer::delta_time connection_interval ) -> decltype(&TT::ll_synchronized_callback_period_update)\n            {\n                Obj.ll_synchronized_callback_period_update( connection_interval, num_calls_, connection_value_ );\n\n                return 0;\n            }\n\n            template < class TT >\n            void call_ll_update( ... )\n            {\n            }\n\n            void setup_timer( delta_time dt )\n            {\n                const bool setup = link_layer().schedule_synchronized_user_timer( dt, delta_time( MaximumExecutionTimeUS ) );\n                static_cast< void >( setup );\n                assert( setup );\n            }\n\n            LinkLayer& link_layer()\n            {\n                return *static_cast< LinkLayer* >( this );\n            }\n\n            void calculate_effective_period( delta_time connection_interval )\n            {\n                const auto interval_us = connection_interval.usec();\n\n                if ( interval_us > MaximumPeriodUS )\n                {\n                    num_calls_         = ( interval_us + MaximumPeriodUS - 1 ) / MaximumPeriodUS;\n                    num_intervals_     = 0;\n                    effective_period_  = delta_time( interval_us / num_calls_ );\n                }\n                else\n                {\n                    num_calls_        = 0;\n                    num_intervals_    = MaximumPeriodUS / interval_us;\n                    effective_period_ = delta_time( num_intervals_ * interval_us );\n                }\n\n                num_intervals_since_anchor_moved_ = 0;\n\n                assert( effective_period_.usec() <= MaximumPeriodUS );\n            }\n\n            delta_time first_timeout() const\n            {\n                return PhaseShiftUS < 0\n                    ? effective_period_ - delta_time::usec( -PhaseShiftUS )\n                    : effective_period_ + delta_time::usec( PhaseShiftUS );\n            }\n\n            delta_time effective_period_;\n\n            unsigned instance_;\n            unsigned latency_;\n\n            // > 1 if there are more than 1 call to the CB at each interval\n            unsigned num_calls_;\n\n            // > 1 if there are more that 1 interval between two CB calls\n            unsigned num_intervals_;\n\n            unsigned num_intervals_since_anchor_moved_;\n\n            typename T::connection connection_value_;\n\n            volatile bool stopped_;\n            volatile bool force_;\n        };\n\n        typedef details::synchronized_connection_event_callback_meta_type meta_type;\n        /** @endcond */\n    };\n\n    /**\n     * @brief Do not user synchronized connection event callbacks\n     *\n     * This is the default.\n     */\n    struct no_synchronized_connection_event_callback\n    {\n        /** @cond HIDDEN_SYMBOLS */\n        template < typename LinkLayer >\n        struct impl {\n            void synchronized_connection_event_callback_new_connection( delta_time )\n            {\n            }\n\n            void synchronized_connection_event_callback_start_changing_connection()\n            {\n            }\n\n            void synchronized_connection_event_callback_connection_changed( delta_time )\n            {\n            }\n\n            void synchronized_connection_event_callback_timeout( bool )\n            {\n            }\n\n            void synchronized_connection_event_callback_disconnect()\n            {\n            }\n        };\n\n        typedef details::synchronized_connection_event_callback_meta_type meta_type;\n        /** @endcond */\n    };\n\n    /**\n     * @brief if this parameter is given to the link layer, some compile time checks are done.\n     *\n     * The compiliation will fail, if the parameters given to synchronized_connection_event_callback<>\n     * fail to provide a garanty, that under all possible connection intervals\n     * - MaximumPeriodUS can be garantied with all possible connection intervals\n     * - PhaseShiftUS is negative and the end of the callback execution leaves enough time\n     *   to start the radio.\n     * - MaximumExecutionTimeUS does not exceed any possible connection interval taking PhaseShiftUS\n     *   and MaximumPeriodUS into account.\n     *\n     * @sa synchronized_connection_event_callback\n     */\n    template < unsigned ExpectedMinimumInterval_US >\n    struct ranged_check_synchronized_connection_event_callback\n    {\n        /** @cond HIDDEN_SYMBOLS */\n        template < typename Radio >\n        static void check( const no_synchronized_connection_event_callback& )\n        {\n        }\n\n        template < typename Radio, typename T, T& Obj, unsigned MaximumPeriodUS, int PhaseShiftUS, unsigned MaximumExecutionTimeUS >\n        static void check( const synchronized_connection_event_callback< T, Obj, MaximumPeriodUS, PhaseShiftUS, MaximumExecutionTimeUS >& )\n        {\n            static_assert( MaximumPeriodUS <= ExpectedMinimumInterval_US,\n                \"To guaranty the timely execution of the callback, the MaximumPeriodUS must be small or equal to the minimum connection interval!\" );\n\n            static_assert( PhaseShiftUS < 0,\n                \"In order to make sure, that the callback is finished when the connection event starts, the callback must start prior to the connection event!\" );\n\n            static_assert( -PhaseShiftUS >= Radio::connection_event_setup_time_us,\n                \"PhaseShiftUS must start before the radios setup time.\" );\n\n            static_assert( -PhaseShiftUS >= Radio::connection_event_setup_time_us + MaximumExecutionTimeUS,\n                \"Callback execution must end before setup time of the configured radio.\" );\n\n            static_assert( MaximumPeriodUS / 2 >= MaximumExecutionTimeUS,\n                \"In worst case, the effective period of the callback invocation is half the requested period and thus must still be large enough for the expected runtimer of the callback.\" );\n\n            static_assert( -PhaseShiftUS < MaximumPeriodUS / 2,\n                \"In worst case, the effective period of the callback invocation is half the requested period and thus must still be small than the phase shift.\" );\n        }\n\n        using meta_type = details::check_synchronized_connection_event_callback_meta_type;\n        /** @endcond */\n    };\n\n    using check_synchronized_connection_event_callback =\n        ranged_check_synchronized_connection_event_callback< 7500u >;\n\n    /**\n     * @brief no compiler time parameter check\n     *\n     * @sa check_synchronized_connection_event_callback\n     */\n    struct no_check_synchronized_connection_event_callback\n    {\n        /** @cond HIDDEN_SYMBOLS */\n        template < typename Radio, class CBs >\n        static void check( const CBs& )\n        {\n        }\n\n        using meta_type = details::check_synchronized_connection_event_callback_meta_type;\n        /** @endcond */\n    };\n\n}\n}\n#endif\n"
  },
  {
    "path": "bluetoe/link_layer/include/bluetoe/connection_events.hpp",
    "content": "#ifndef BLUETOE_LINK_LAYER_CONNECTION_EVENT_HPP\n#define BLUETOE_LINK_LAYER_CONNECTION_EVENT_HPP\n\nnamespace bluetoe {\nnamespace link_layer {\n\n    /**\n     * @brief set of events, that could have happend during a connection event\n     *\n     * This is used by the radio to give some details about, what happend in the last\n     * connection event.\n     */\n    struct connection_event_events\n    {\n        /**\n         * @brief The last, not empty PDU, that was send out during the connection event\n         *        was _not_ acknowlaged by the central yet.\n         */\n        bool unacknowledged_data;\n\n        /**\n         * @brief At the last connection event, there was at least one not empty PDU received from\n         *        the central.\n         */\n        bool last_received_not_empty;\n\n        /**\n         * @brief At the last connection event, there was at least one PDU transmitted, that was not empty.\n         */\n        bool last_transmitted_not_empty;\n\n        /**\n         * @brief The last PDU received at the connection event, had the MD flag beeing set.\n         */\n        bool last_received_had_more_data;\n\n        /**\n         * @brief There is pending, outgoing data\n         */\n        bool pending_outgoing_data;\n\n        /**\n         * @brief there was a CRC error at the last connection event\n         */\n        bool error_occured;\n\n        /**\n         * @brief c'tor to reset all flags\n         */\n        connection_event_events()\n            : unacknowledged_data( false )\n            , last_received_not_empty( false )\n            , last_transmitted_not_empty( false )\n            , last_received_had_more_data( false )\n            , pending_outgoing_data( false )\n            , error_occured( false )\n        {\n        }\n\n        /**\n         * @brief c'tor to define all flags\n         */\n        connection_event_events(\n            bool unacknowledged_data_present,\n            bool last_received_not_empty_present,\n            bool last_transmitted_not_empty_happend,\n            bool last_received_had_more_data_present,\n            bool pending_outgoing_data_present,\n            bool error_present )\n            : unacknowledged_data( unacknowledged_data_present )\n            , last_received_not_empty( last_received_not_empty_present )\n            , last_transmitted_not_empty( last_transmitted_not_empty_happend )\n            , last_received_had_more_data( last_received_had_more_data_present )\n            , pending_outgoing_data( pending_outgoing_data_present )\n            , error_occured( error_present )\n        {\n        }\n    };\n\n}\n}\n\n#endif\n"
  },
  {
    "path": "bluetoe/link_layer/include/bluetoe/default_pdu_layout.hpp",
    "content": "#ifndef BLUETOE_LINK_LAYER_DEFAULT_PDU_LAYOUT_HPP\n#define BLUETOE_LINK_LAYER_DEFAULT_PDU_LAYOUT_HPP\n\n#include <bluetoe/bits.hpp>\n#include <bluetoe/buffer.hpp>\n\nnamespace bluetoe {\nnamespace link_layer {\n\n    namespace details {\n        // usefull overloads\n        template < class Base >\n        struct layout_base\n        {\n            static std::uint16_t header( const read_buffer& pdu )\n            {\n                assert( pdu.size >= Base::data_channel_pdu_memory_size( 0 ) );\n\n                return Base::header( pdu.buffer );\n            }\n\n            static std::uint16_t header( const write_buffer& pdu )\n            {\n                assert( pdu.size >= Base::data_channel_pdu_memory_size( 0 ) );\n\n                return Base::header( pdu.buffer );\n            }\n\n            static void header( const read_buffer& pdu, std::uint16_t header_value )\n            {\n                assert( pdu.size >= Base::data_channel_pdu_memory_size( 0 ) );\n\n                Base::header( pdu.buffer, header_value );\n            }\n        };\n    }\n    /**\n     * @brief implements a PDU layout, where in memory and over the air layout are equal.\n     *\n     * The type is ment to be used as member of a scheduled_radio implementation.\n     */\n    struct default_pdu_layout : details::layout_base< default_pdu_layout >{\n        /**\n         * @brief fixed 16 bit size of a LL PDU\n         */\n        static constexpr std::size_t header_size = sizeof( std::uint16_t );\n\n        using details::layout_base< default_pdu_layout >::header;\n\n        /**\n         * @brief retrieves the 16 bit LL header from a PDU.\n         */\n        static std::uint16_t header( const std::uint8_t* pdu )\n        {\n            return ::bluetoe::details::read_16bit( pdu );\n        }\n\n        /**\n         * @brief sets the 16 but LL header for the pdu\n         */\n        static void header( std::uint8_t* pdu, std::uint16_t header_value )\n        {\n            ::bluetoe::details::write_16bit( pdu, header_value );\n        }\n\n        /**\n         * @brief returns a begin and end pointer to the body of a PDU\n         *\n         * That pair can be used to modify the body\n         */\n        static std::pair< std::uint8_t*, std::uint8_t* > body( const read_buffer& pdu )\n        {\n            assert( pdu.size >= header_size );\n\n            return { &pdu.buffer[ header_size ], &pdu.buffer[ pdu.size ] };\n        }\n\n        /**\n         * @brief returns a begin and end pointer to the body of a PDU\n         */\n        static std::pair< const std::uint8_t*, const std::uint8_t* > body( const write_buffer& pdu )\n        {\n            assert( pdu.size >= header_size );\n\n            return { &pdu.buffer[ header_size ], &pdu.buffer[ pdu.size ] };\n        }\n\n        /**\n         * @brief returns the overall, required buffer size for a PDU with the given\n         *        payload_size.\n         */\n        static constexpr std::size_t data_channel_pdu_memory_size( std::size_t payload_size )\n        {\n            return header_size + payload_size;\n        }\n    };\n\n    /**\n     * @brief type to associate a radio implementation with the corresponding layout\n     *\n     * Must be specialized by radio implementations that do not use the default_pdu_layout.\n     */\n    template < typename Radio >\n    struct pdu_layout_by_radio {\n        /**\n         * @brief the layout to be applied when Radio is used\n         */\n        using pdu_layout = default_pdu_layout;\n    };\n\n}\n}\n\n#endif\n"
  },
  {
    "path": "bluetoe/link_layer/include/bluetoe/delta_time.hpp",
    "content": "#ifndef BLUETOE_LINK_LAYER_DELTA_TIME_HPP\n#define BLUETOE_LINK_LAYER_DELTA_TIME_HPP\n\n#include <cstdint>\n#include <iosfwd>\n\nnamespace bluetoe {\nnamespace link_layer {\n\n    /**\n     * @brief positiv time quantum used to express distance in time.\n     */\n    class delta_time\n    {\n    public:\n        constexpr delta_time() : usec_( 0 )\n        {\n        }\n\n        /**\n         * @brief creates a delta_time from a positive number of µs (Microseconds).\n         */\n        constexpr explicit delta_time( std::uint32_t usec ) : usec_( usec )\n        {\n        }\n\n        /**\n         * @copydoc delta_time::delta_time( std::uint32_t )\n         */\n        static delta_time usec( std::uint32_t usec );\n\n        /**\n         * @brief creates a delta_time from a positive number of ms (milliseconds).\n         */\n        static delta_time msec( std::uint32_t msec );\n\n        /**\n         * @brief creates a delta_time from a positive number of s (seconds).\n         */\n        static delta_time seconds( int s );\n\n        /**\n         * @brief creates a delta_time denoting the distance from now to now. Aka 0.\n         */\n        static delta_time now();\n\n        /**\n         * @brief prints this on the given stream in a human readable manner\n         */\n        void print( std::ostream& ) const;\n\n        /**\n         * @brief adds rhs to this\n         */\n        delta_time& operator+=( const delta_time& rhs );\n\n        /**\n         * @brief substracts rhs from this.\n         * @pre *this >= rhs\n         */\n        delta_time& operator-=( const delta_time& rhs );\n\n        /**\n         * @brief scales this by rhs\n         */\n        delta_time& operator*=( unsigned rhs );\n\n        /**\n         * @brief devides this by rhs\n         * @pre this* != delta_time()\n         */\n        unsigned operator/(const delta_time& rhs );\n\n        /**\n         * @brief returns true, if this is smaller than rhs\n         */\n        bool operator<( const delta_time& rhs ) const;\n\n        /**\n         * @brief returns true, if this is smaller than or equal to rhs\n         */\n        bool operator<=( const delta_time& rhs ) const;\n\n        /**\n         * @brief returns true, if this is larger than rhs\n         */\n        bool operator>( const delta_time& rhs ) const;\n\n        /**\n         * @brief returns true, if this is larger than or equal to rhs\n         */\n        bool operator>=( const delta_time& rhs ) const;\n\n        /**\n         * @brief returns true, if this is equal to rhs\n         */\n        bool operator==( const delta_time& rhs ) const;\n\n        /**\n         * @brief returns false, if this is equal to rhs\n         */\n        bool operator!=( const delta_time& rhs ) const;\n\n        /**\n         * @brief returns represented time distance as a number of µs.\n         *\n         * delta_time( x ).usec() == x\n         */\n        std::uint32_t usec() const;\n\n        /**\n         * @brief returns true, if the represented time distance is zero.\n         *\n         * delta_time( 0 ).zero() == true\n         */\n        bool zero() const;\n\n        /**\n         * @brief returns the given parts per million.\n         *\n         * delta_time::usec( 1000000 ).ppm( 44 ).usec() == 44\n         * @param part the parts of a million. The parameter have to in the range 0-1000\n         *        to not cause overflows.\n         */\n        delta_time ppm( unsigned part ) const;\n    private:\n        std::uint32_t usec_;\n    };\n\n    /**\n     * @brief prints the given delta_time on the given stream in a human readable manner\n     * @relates delta_time\n     */\n    std::ostream& operator<<( std::ostream&, const delta_time& );\n\n    /**\n     * @brief returns the sum of both delta_times\n     * @relates delta_time\n     */\n    delta_time operator+( delta_time lhs, delta_time rhs );\n\n    /**\n     * @brief returns the difference of both delta_times\n     * @relates delta_time\n     */\n    delta_time operator-( delta_time lhs, delta_time rhs );\n\n    /**\n     * @brief scales the given delta_time by the given factor\n     * @relates delta_time\n     */\n    delta_time operator*( delta_time lhs, unsigned rhs );\n\n    /**\n     * @copydoc operator*( delta_time, unsigned )\n     */\n    delta_time operator*( unsigned lhs, delta_time rhs );\n\n}\n}\n#endif\n"
  },
  {
    "path": "bluetoe/link_layer/include/bluetoe/l2cap_signaling_channel.hpp",
    "content": "#ifndef BLUETOE_LINK_LAYER_L2CAP_SIGNALING_CHANNEL_HPP\n#define BLUETOE_LINK_LAYER_L2CAP_SIGNALING_CHANNEL_HPP\n\n#include <bluetoe/ll_meta_types.hpp>\n#include <bluetoe/codes.hpp>\n#include <bluetoe/l2cap_channels.hpp>\n\n#include <cstdlib>\n#include <cstdint>\n\nnamespace bluetoe {\n\nnamespace details {\n    struct signaling_channel_meta_type {};\n}\n\nnamespace l2cap {\n\n    /**\n     * @brief very basic l2cap signaling channel implementation\n     *\n     * Currently the implementation allows just for sending connection parameter update requests.\n     */\n    template < typename ... Options >\n    class signaling_channel\n    {\n    public:\n        signaling_channel();\n\n        /**\n         * @brief input from the l2cap layer\n         */\n        template < typename ConnectionData >\n        void l2cap_input( const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size, ConnectionData& );\n\n        /**\n         * @brief output to the l2cap layer\n         */\n        template < typename ConnectionData >\n        void l2cap_output( std::uint8_t* output, std::size_t& out_size, ConnectionData& );\n\n        /**\n         * @brief queues a connection parameter update request.\n         *\n         * Function returns true on success. If the a request is still queued, but was not responded jet,\n         * the function will return false.\n         */\n        bool connection_parameter_update_request( std::uint16_t interval_min, std::uint16_t interval_max, std::uint16_t latency, std::uint16_t timeout );\n\n        /**\n         * @brief supported MTU size\n         */\n        constexpr std::size_t channel_mtu_size() const;\n\n        /** @cond HIDDEN_SYMBOLS */\n        static constexpr std::uint16_t channel_id               = l2cap_channel_ids::signaling;\n        static constexpr std::size_t   minimum_channel_mtu_size = bluetoe::details::default_att_mtu_size;\n        static constexpr std::size_t   maximum_channel_mtu_size = bluetoe::details::default_att_mtu_size;\n\n        template < class PreviousData >\n        using channel_data_t = PreviousData;\n\n        struct meta_type :\n            bluetoe::details::signaling_channel_meta_type,\n            bluetoe::link_layer::details::valid_link_layer_option_meta_type {};\n        /** @endcond */\n    private:\n        void reject_command( const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size );\n\n        static constexpr std::uint8_t command_reject_code                       = 0x01;\n        static constexpr std::uint8_t connection_parameter_update_request_code  = 0x12;\n        static constexpr std::uint8_t connection_parameter_update_response_code = 0x13;\n\n        std::uint16_t interval_min_;\n        std::uint16_t interval_max_;\n        std::uint16_t latency_;\n        std::uint16_t timeout_;\n\n        enum {\n            idle,\n            queued,\n            transmitted\n        } pending_status_;\n\n        static constexpr std::uint8_t   invalid_identifier = 0x00;\n        std::uint8_t identifier_;\n    };\n\n    /**\n     * @brief signaling channel implementations that does simply nothing\n     */\n    class no_signaling_channel\n    {\n    public:\n        /**\n         * @copydoc signaling_channel::l2cap_input\n         */\n        template < typename ConnectionData >\n        void l2cap_input( const std::uint8_t*, std::size_t, std::uint8_t*, std::size_t& out_size, ConnectionData& )\n        {\n            out_size = 0;\n        }\n\n        /**\n         * @copydoc signaling_channel::l2cap_output\n         */\n        template < typename ConnectionData >\n        void l2cap_output( std::uint8_t*, std::size_t& out_size, ConnectionData& )\n        {\n            out_size = 0;\n        }\n\n        /**\n         * @copydoc signaling_channel::connection_parameter_update_request\n         */\n        bool connection_parameter_update_request( std::uint16_t, std::uint16_t, std::uint16_t, std::uint16_t )\n        {\n            return false;\n        }\n\n        /**\n         * @brief supported MTU size\n         */\n        constexpr std::size_t channel_mtu_size() const\n        {\n            return bluetoe::details::default_att_mtu_size;\n        }\n\n        /** @cond HIDDEN_SYMBOLS */\n        static constexpr std::uint16_t channel_id               = l2cap_channel_ids::signaling;\n        static constexpr std::size_t   minimum_channel_mtu_size = 0;\n        static constexpr std::size_t   maximum_channel_mtu_size = 0;\n\n        template < class PreviousData >\n        using channel_data_t = PreviousData;\n\n        typedef bluetoe::details::signaling_channel_meta_type meta_type;\n        /** @endcond */\n    };\n\n    template < typename ... Options >\n    signaling_channel< Options... >::signaling_channel()\n        : pending_status_( idle )\n        , identifier_( 0x01 )\n    {\n    }\n\n    template < typename ... Options >\n    template < typename ConnectionData >\n    void signaling_channel< Options... >::l2cap_input( const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size, ConnectionData& )\n    {\n        const std::uint8_t code = in_size > 0 ? input[ 0 ] : 0;\n\n        if ( code == connection_parameter_update_response_code && pending_status_ == transmitted )\n        {\n            pending_status_ = idle;\n            identifier_ = static_cast< std::uint8_t >( identifier_ + 1 );\n\n            if ( identifier_ == invalid_identifier )\n                identifier_ = static_cast< std::uint8_t >( identifier_ + 1 );\n\n            out_size = 0;\n        }\n        else\n        {\n            reject_command( input, in_size, output, out_size );\n        }\n    }\n\n    template < typename ... Options >\n    template < typename ConnectionData >\n    void signaling_channel< Options... >::l2cap_output( std::uint8_t* output, std::size_t& out_size, ConnectionData& )\n    {\n        static constexpr std::size_t    pdu_size = 8 + 4;\n        assert( out_size >= pdu_size );\n\n        if ( pending_status_ == queued )\n        {\n            pending_status_ = transmitted;\n\n            out_size = pdu_size;\n            output[ 0 ] = connection_parameter_update_request_code;\n            output[ 1 ] = identifier_;\n            output[ 2 ] = pdu_size - 4;\n            output[ 3 ] = 0;\n            output[ 4 ] = static_cast< std::uint8_t >( interval_min_ );\n            output[ 5 ] = static_cast< std::uint8_t >( interval_min_ >> 8 );\n            output[ 6 ] = static_cast< std::uint8_t >( interval_max_ );\n            output[ 7 ] = static_cast< std::uint8_t >( interval_max_ >> 8 );\n            output[ 8 ] = static_cast< std::uint8_t >( latency_ );\n            output[ 9 ] = static_cast< std::uint8_t >( latency_ >> 8 );\n            output[ 10 ] = static_cast< std::uint8_t >( timeout_ );\n            output[ 11 ] = static_cast< std::uint8_t >( timeout_ >> 8 );\n        }\n        else\n        {\n            out_size = 0;\n        }\n    }\n\n    template < typename ... Options >\n    bool signaling_channel< Options... >::connection_parameter_update_request( std::uint16_t interval_min, std::uint16_t interval_max, std::uint16_t latency, std::uint16_t timeout )\n    {\n        if ( pending_status_ == idle )\n        {\n            interval_min_ = interval_min;\n            interval_max_ = interval_max;\n            latency_      = latency;\n            timeout_      = timeout;\n\n            pending_status_ = queued;\n            return true;\n        }\n\n        return false;\n    }\n\n    template < typename ... Options >\n    constexpr std::size_t signaling_channel< Options... >::channel_mtu_size() const\n    {\n        return bluetoe::details::default_att_mtu_size;\n    }\n\n    template < typename ... Options >\n    void signaling_channel< Options... >::reject_command( const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size )\n    {\n        static constexpr std::size_t    pdu_size = 6;\n        static constexpr std::uint16_t  command_not_understood = 0;\n        assert( out_size >= pdu_size );\n        out_size = 0;\n\n        if ( in_size < 2 )\n            return;\n\n        const std::uint8_t identifier = input[ 1 ];\n\n        if ( identifier == invalid_identifier )\n            return;\n\n        out_size = pdu_size;\n        output[ 0 ] = command_reject_code;\n        output[ 1 ] = identifier;\n        output[ 2 ] = 2;                    // length\n        output[ 3 ] = 0;                    // length\n        output[ 4 ] = static_cast< std::uint8_t >( command_not_understood );\n        output[ 5 ] = static_cast< std::uint8_t >( command_not_understood >> 8 );\n    }\n}\n}\n\n#endif\n"
  },
  {
    "path": "bluetoe/link_layer/include/bluetoe/link_layer.hpp",
    "content": "#ifndef BLUETOE_LINK_LAYER_LINK_LAYER_HPP\n#define BLUETOE_LINK_LAYER_LINK_LAYER_HPP\n\n#include <bluetoe/buffer.hpp>\n#include <bluetoe/delta_time.hpp>\n#include <bluetoe/ll_l2cap_sdu_buffer.hpp>\n#include <bluetoe/ll_options.hpp>\n#include <bluetoe/phy_encodings.hpp>\n#include <bluetoe/address.hpp>\n#include <bluetoe/channel_map.hpp>\n#include <bluetoe/notification_queue.hpp>\n#include <bluetoe/connection_callbacks.hpp>\n#include <bluetoe/connection_event_callback.hpp>\n#include <bluetoe/l2cap_signaling_channel.hpp>\n#include <bluetoe/white_list.hpp>\n#include <bluetoe/advertising.hpp>\n#include <bluetoe/attribute.hpp>\n#include <bluetoe/meta_types.hpp>\n#include <bluetoe/meta_tools.hpp>\n#include <bluetoe/security_manager.hpp>\n#include <bluetoe/codes.hpp>\n#include <bluetoe/encryption.hpp>\n#include <bluetoe/l2cap.hpp>\n#include <bluetoe/connection_events.hpp>\n#include <bluetoe/peripheral_latency.hpp>\n\n#include <algorithm>\n#include <cassert>\n\nnamespace bluetoe {\n    namespace details {\n        class notification_data;\n    }\n\nnamespace link_layer {\n\n    template <\n        class Server,\n        template <\n            std::size_t TransmitSize,\n            std::size_t ReceiveSize,\n            class CallBack\n        >\n        class ScheduledRadio,\n        typename ... Options\n    >\n    class link_layer;\n\n    namespace details {\n        template < typename ... Options >\n        struct buffer_sizes\n        {\n            typedef typename ::bluetoe::details::find_by_meta_type<\n                buffer_sizes_meta_type,\n                Options...,\n                ::bluetoe::link_layer::buffer_sizes<>  // default\n            >::type s_type;\n\n            static constexpr std::size_t tx_size = s_type::transmit_buffer_size;\n            static constexpr std::size_t rx_size = s_type::receive_buffer_size;\n        };\n\n        template < typename SecurityFunctions, typename Server, typename ... Options >\n        struct security_manager {\n            using default_sm = typename bluetoe::details::select_type<\n                bluetoe::details::requires_encryption_support_t< Server >::value,\n                bluetoe::lesc_security_manager,\n                bluetoe::no_security_manager\n            >::type;\n\n            using impl = typename bluetoe::details::find_by_meta_type<\n                bluetoe::details::security_manager_meta_type,\n                Options...,\n                default_sm >::type;\n\n            using type = typename impl::template impl< SecurityFunctions, Options... >;\n        };\n\n        template < typename ... Options >\n        struct signaling_channel {\n            typedef typename bluetoe::details::find_by_meta_type<\n                bluetoe::details::signaling_channel_meta_type,\n                Options...,\n                bluetoe::l2cap::no_signaling_channel >::type type;\n        };\n\n        template < typename LinkLayer, typename ... Options >\n        struct connection_callbacks\n        {\n            using type = typename bluetoe::details::find_by_meta_type<\n                connection_callbacks_meta_type,\n                Options...,\n                no_connection_callbacks >::type;\n        };\n\n        template < typename Radio, typename LinkLayer, typename ... Options >\n        struct white_list\n        {\n            typedef typename bluetoe::details::find_by_meta_type<\n                white_list_meta_type,\n                Options...,\n                no_white_list >::type list;\n\n            typedef typename list::template impl< Radio, LinkLayer > type;\n        };\n\n        /*\n         * The Part of link layer, that handles security related stuff is\n         * factored out, to not have unnessary code, in case that no\n         * security relevant code is required\n         */\n        struct link_layer_security_impl\n        {\n            template < class LinkLayer >\n            class impl\n            {\n            public:\n                impl()\n                    : has_key_( false )\n                    , encryption_in_progress_( false )\n                {}\n\n                LinkLayer& that()\n                {\n                    return static_cast< LinkLayer& >( *this );\n                }\n\n                bool handle_encryption_pdus( std::uint8_t opcode, std::uint8_t size, const write_buffer& pdu, read_buffer write, bool& commit )\n                {\n                    using namespace ::bluetoe::details;\n\n                    using layout_t = typename pdu_layout_by_radio< typename LinkLayer::radio_t >::pdu_layout;\n\n                    bool encryption_changed = false;\n\n                    if ( opcode == LinkLayer::LL_ENC_REQ && size == 23 )\n                    {\n                        encryption_in_progress_ = true;\n                        fill< layout_t >( write, { LinkLayer::ll_control_pdu_code, 1 + 8 + 4, LinkLayer::LL_ENC_RSP } );\n\n                        const std::uint8_t* const pdu_body = layout_t::body( pdu ).first;\n\n                        const std::uint64_t rand = read_64bit( pdu_body +1 );\n                        const std::uint16_t ediv = read_16bit( pdu_body +9 );\n                        const std::uint64_t skdm = read_64bit( pdu_body +11 );\n                        const std::uint32_t ivm  = read_32bit( pdu_body +19 );\n                              std::uint64_t skds = 0;\n                              std::uint32_t ivs  = 0;\n\n                        bluetoe::details::uint128_t key;\n                        std::tie( has_key_, key ) = that().connection_data_.find_key( ediv, rand );\n\n                        // setup encryption\n                        std::tie( skds, ivs ) = that().setup_encryption( key, skdm, ivm );\n\n                        std::uint8_t* write_body = layout_t::body( write ).first;\n                        bluetoe::details::write_64bit( &write_body[ 1 ], skds );\n                        bluetoe::details::write_32bit( &write_body[ 9 ], ivs );\n                    }\n                    else if ( opcode == LinkLayer::LL_START_ENC_RSP && size == 1 )\n                    {\n                        fill< layout_t >( write, { LinkLayer::ll_control_pdu_code, 1, LinkLayer::LL_START_ENC_RSP } );\n                        that().start_transmit_encrypted();\n                        encryption_changed = that().connection_data_.is_encrypted( true );\n\n                        if ( encryption_changed )\n                            that().connection_data_.restore_bonded_cccds( that().connection_data_ );\n\n                    }\n                    else if ( opcode == LinkLayer::LL_PAUSE_ENC_REQ && size == 1 )\n                    {\n                        fill< layout_t >( write, { LinkLayer::ll_control_pdu_code, 1, LinkLayer::LL_PAUSE_ENC_RSP } );\n                        that().stop_receive_encrypted();\n                        encryption_changed = that().connection_data_.is_encrypted( false );\n                    }\n                    else if ( opcode == LinkLayer::LL_PAUSE_ENC_RSP && size == 1 )\n                    {\n                        that().stop_transmit_encrypted();\n                        encryption_changed = that().connection_data_.is_encrypted( false );\n\n                        commit = false;\n                    }\n                    else\n                    {\n                        return false;\n                    }\n\n                    if ( encryption_changed )\n                    {\n                        that().connection_data_.pairing_status(that().connection_data_.local_device_pairing_status());\n                        that().connection_changed( that().details(), that().connection_data_, static_cast< typename LinkLayer::radio_t& >( that() ) );\n                    }\n\n                    return true;\n                }\n\n                void transmit_pending_security_pdus()\n                {\n                    using layout_t = typename pdu_layout_by_radio< typename LinkLayer::radio_t >::pdu_layout;\n\n                    if ( !encryption_in_progress_ )\n                        return;\n\n                    auto out_buffer = that().allocate_ll_transmit_buffer( LinkLayer::maximum_ll_payload_size );\n                    if ( out_buffer.empty() )\n                        return;\n\n                    if ( has_key_ )\n                    {\n                        fill< layout_t >( out_buffer, {\n                            LinkLayer::ll_control_pdu_code, 1, LinkLayer::LL_START_ENC_REQ } );\n\n                        that().start_receive_encrypted();\n                        that().commit_ll_transmit_buffer( out_buffer );\n                    }\n                    else\n                    {\n                        that().reject( LinkLayer::LL_ENC_REQ, LinkLayer::err_pin_or_key_missing, out_buffer );\n                        that().commit_ll_transmit_buffer( out_buffer );\n                    }\n\n                    encryption_in_progress_ = false;\n                }\n\n                void reset_encryption()\n                {\n                    that().connection_data_.is_encrypted( false );\n                    that().stop_receive_encrypted();\n                    that().stop_transmit_encrypted();\n                }\n\n            private:\n                bool has_key_;\n                bool encryption_in_progress_;\n            };\n\n            using link_state = bluetoe::details::link_state;\n        };\n\n        struct link_layer_no_security_impl\n        {\n            template < class LinkLayer >\n            struct impl\n            {\n                bool handle_encryption_pdus( std::uint8_t, std::uint8_t, write_buffer, read_buffer, bool& )\n                {\n                    return false;\n                }\n\n                void transmit_pending_security_pdus()\n                {\n                }\n\n                void reset_encryption()\n                {\n                }\n            };\n\n            using link_state = bluetoe::details::link_state_no_security;\n        };\n\n        /*\n         * The Part of link layer, that handles PHY update requests\n         */\n        struct phy_update_request_impl\n        {\n            template < class LL >\n            bool handle_phy_request( std::uint8_t opcode, std::uint8_t size, const write_buffer& pdu, read_buffer& write, LL& link_layer, bool& commit )\n            {\n                assert( link_layer.defered_ll_control_pdu_.buffer == nullptr );\n\n                using layout_t = typename pdu_layout_by_radio< typename LL::radio_t >::pdu_layout;\n\n                if ( opcode == LL::LL_PHY_REQ && size == 3 )\n                {\n                    fill< layout_t >( write, {\n                        LL::ll_control_pdu_code, 3,\n                        LL::LL_PHY_RSP,\n                        phy_ll_encoding::le_1m_phy | phy_ll_encoding::le_2m_phy,\n                        phy_ll_encoding::le_1m_phy | phy_ll_encoding::le_2m_phy } );\n\n                    return true;\n                }\n\n                if ( opcode == LL::LL_PHY_UPDATE_IND && size == 5 )\n                {\n                    const std::uint8_t* const pdu_body = layout_t::body( pdu ).first;\n\n                    const std::uint8_t c_to_p = pdu_body[ 1 ];\n                    const std::uint8_t p_to_c = pdu_body[ 2 ];\n\n                    if ( !valid_phy_encoding( c_to_p ) || !valid_phy_encoding( p_to_c ) )\n                        return false;\n\n                    commit = false;\n\n                    if ( c_to_p == phy_ll_encoding::le_unchanged_coding\n                      && p_to_c == phy_ll_encoding::le_unchanged_coding )\n                    {\n                        link_layer.phy_update( c_to_p, p_to_c, link_layer.connection_data_, link_layer );\n                        return true;\n                    }\n\n                    link_layer.defered_ll_control_pdu_     = pdu;\n                    link_layer.defered_conn_event_counter_ = ::bluetoe::details::read_16bit( pdu_body + 3 );\n\n                    return true;\n                }\n\n                return false;\n            }\n\n            template < class LL >\n            bool handle_pending_phy_request( std::uint8_t opcode, LL& link_layer )\n            {\n                assert( link_layer.defered_ll_control_pdu_.buffer );\n\n                using layout_t = typename pdu_layout_by_radio< typename LL::radio_t >::pdu_layout;\n\n                if ( opcode == LL::LL_PHY_UPDATE_IND )\n                {\n                    const std::uint8_t* const pdu_body = layout_t::body( link_layer.defered_ll_control_pdu_ ).first;\n\n                    const auto c_to_p = static_cast< phy_ll_encoding::phy_ll_encoding_t >( pdu_body[ 1 ] );\n                    const auto p_to_c = static_cast< phy_ll_encoding::phy_ll_encoding_t >( pdu_body[ 2 ] );\n                    link_layer.defered_ll_control_pdu_ = { nullptr, 0 };\n                    link_layer.radio_set_phy( c_to_p, p_to_c );\n\n                    link_layer.phy_update( c_to_p, p_to_c, link_layer.connection_data_, link_layer );\n                    return true;\n                }\n\n                return false;\n            }\n\n            template < class LL >\n            void reset_phy( LL& link_layer )\n            {\n                link_layer.radio_set_phy( phy_ll_encoding::le_1m_phy, phy_ll_encoding::le_1m_phy );\n            }\n\n        private:\n            bool valid_phy_encoding( std::uint8_t c ) const\n            {\n                return c == phy_ll_encoding::le_unchanged_coding\n                    || c == phy_ll_encoding::le_1m_phy\n                    || c == phy_ll_encoding::le_2m_phy;\n            }\n        };\n\n        struct no_phy_update_request_impl\n        {\n            template < class LL >\n            bool handle_phy_request( std::uint8_t, std::uint8_t, const write_buffer&, read_buffer, LL&, bool& )\n            {\n                return false;\n            }\n\n            template < class LL >\n            bool handle_pending_phy_request( std::uint8_t, LL& )\n            {\n                return false;\n            }\n\n            template < class LL >\n            void reset_phy( LL& )\n            {}\n        };\n\n        template < class Server, class LinkLayer >\n        using select_link_layer_security_impl =\n            typename bluetoe::details::select_type<\n                bluetoe::details::requires_encryption_support_t< Server >::value,\n                link_layer_security_impl,\n                link_layer_no_security_impl\n            >::type::template impl< LinkLayer >;\n\n        template < class Server >\n        using select_link_layer_security_link_state =\n            typename bluetoe::details::select_type<\n                bluetoe::details::requires_encryption_support_t< Server >::value,\n                link_layer_security_impl,\n                link_layer_no_security_impl\n            >::type::link_state;\n\n        template < class Radio >\n        using select_phy_update_impl =\n            typename bluetoe::details::select_type<\n                Radio::hardware_supports_2mbit,\n                phy_update_request_impl,\n                no_phy_update_request_impl\n            >::type;\n\n        /*\n         * Construct the l2cap layer\n         */\n        template <\n            class Server,\n            template <\n                std::size_t TransmitSize,\n                std::size_t ReceiveSize,\n                class CallBack\n            >\n            class ScheduledRadio,\n            typename ... Options\n        >\n        struct l2cap_layer {\n            using link_layer_t = link_layer< Server, ScheduledRadio, Options... >;\n\n            struct default_l2cap_layer {\n\n                using gatt_server       = Server;\n\n                using signaling_channel = typename details::signaling_channel<\n                    Options... >::type;\n\n                using security_manager  = typename details::security_manager<\n                    link_layer_t,\n                    gatt_server, Options...\n                >::type;\n\n                template < class LinkLayer >\n                using l2cap_layer = bluetoe::details::l2cap<\n                    LinkLayer,\n                    details::select_link_layer_security_link_state< gatt_server >,\n                    gatt_server,\n                    signaling_channel,\n                    security_manager\n                >;\n\n                using meta_type = details::custom_l2cap_layer_meta_type;\n            };\n\n            using container = typename bluetoe::details::find_by_meta_type<\n                details::custom_l2cap_layer_meta_type,\n                Options...,\n                default_l2cap_layer\n            >::type;\n\n            using impl = typename container::template l2cap_layer< link_layer_t >;\n            static constexpr std::size_t required_minimum_l2cap_buffer_size = impl::maximum_mtu_size;\n        };\n\n        template < typename ...Options >\n        using connection_latency_state_t = peripheral_latency_state<\n            typename bluetoe::details::find_by_meta_type<\n                peripheral_latency_meta_type,\n                Options...,\n                periperal_latency_default_configuration >::type\n            >;\n\n        template < class Base, typename ...Options >\n        using select_user_timer_impl = typename bluetoe::details::find_by_meta_type<\n            synchronized_connection_event_callback_meta_type,\n            Options...,\n            no_synchronized_connection_event_callback\n        >::type::template impl< Base >;\n    }\n\n    /**\n     * @brief link layer implementation\n     *\n     * Implements a binding to a server by implementing a link layer on top of a ScheduleRadio device.\n     *\n     * @sa connectable_undirected_advertising\n     * @sa connectable_directed_advertising\n     * @sa scannable_undirected_advertising\n     * @sa non_connectable_undirected_advertising\n     * @sa auto_start_advertising\n     * @sa no_auto_start_advertising\n     */\n    template <\n        class Server,\n        template <\n            std::size_t TransmitSize,\n            std::size_t ReceiveSize,\n            class CallBack\n        >\n        class ScheduledRadio,\n        typename ... Options\n    >\n    class link_layer :\n        public bluetoe::link_layer::ll_l2cap_sdu_buffer<\n            ScheduledRadio<\n                details::buffer_sizes< Options... >::tx_size,\n                details::buffer_sizes< Options... >::rx_size,\n                link_layer< Server, ScheduledRadio, Options... >\n            >,\n            link_layer< Server, ScheduledRadio, Options... >,\n            details::l2cap_layer< Server, ScheduledRadio, Options... >::required_minimum_l2cap_buffer_size\n        >,\n        public details::white_list<\n            ScheduledRadio<\n                details::buffer_sizes< Options... >::tx_size,\n                details::buffer_sizes< Options... >::rx_size,\n                link_layer< Server, ScheduledRadio, Options... >\n            >,\n            link_layer< Server, ScheduledRadio, Options... >,\n            Options... >::type,\n        public details::select_advertiser_implementation<\n            link_layer< Server, ScheduledRadio, Options... >,\n            Options... >,\n        public details::l2cap_layer< Server, ScheduledRadio, Options... >::impl,\n        private details::connection_callbacks< link_layer< Server, ScheduledRadio, Options... >, Options... >::type,\n        private details::select_link_layer_security_impl< Server, link_layer< Server, ScheduledRadio, Options... > >,\n        public details::connection_latency_state_t< Options... >,\n        private details::select_phy_update_impl< ScheduledRadio<\n                details::buffer_sizes< Options... >::tx_size,\n                details::buffer_sizes< Options... >::rx_size,\n                link_layer< Server, ScheduledRadio, Options... >\n            > >,\n        public details::select_user_timer_impl<\n            link_layer< Server, ScheduledRadio, Options... >, Options ... >,\n        public bluetoe::details::find_by_meta_type<\n            details::ll_pdu_receive_data_callback_meta_type,\n            Options...,\n            no_l2cap_callback\n        >::type,\n        public bluetoe::details::find_by_meta_type<\n            details::desired_connection_parameters_meta_type,\n            Options...,\n            no_desired_connection_parameters\n        >::type\n    {\n    public:\n        link_layer();\n\n        /**\n         * @brief this function passes the CPU to the link layer implementation\n         *\n         * This function should return on certain events to alow user code to do\n         * usefull things. Details depend on the ScheduleRadio implemention.\n         */\n        void run();\n\n        /**\n         * @brief call back that will be called when the central responds to an advertising PDU\n         * @sa scheduled_radio::schedule_advertisment_and_receive\n         */\n        void adv_received( const read_buffer& receive );\n\n        /**\n         * @brief call back that will be called when the central does not respond to an advertising PDU\n         * @sa scheduled_radio::schedule_advertisment_and_receive\n         */\n        void adv_timeout();\n\n        /**\n         * @brief call back that will be called when connect event times out\n         * @sa scheduled_radio::schedule_connection_event\n         */\n        void timeout();\n\n        /**\n         * @brief call back that will be called after a connect event was closed.\n         * @sa scheduled_radio::schedule_connection_event\n         */\n        void end_event( connection_event_events evts );\n\n        /**\n         * @brief call back that will be called on expired user timer.\n         */\n        void user_timer( bool anchor_moved );\n\n        /**\n         * @brief call back that will try to reschedule the connection event\n         */\n        void try_event_cancelation();\n\n        /**\n         * @brief initiating the change of communication parameters of an established connection\n         *\n         * If it was not possible to initiate the connection parameter update, the function returns false.\n         * @todo Add parameter that identifies the connection.\n         */\n        bool connection_parameter_update_request( std::uint16_t interval_min, std::uint16_t interval_max, std::uint16_t latency, std::uint16_t timeout );\n\n        /**\n         * @brief initiate a link layer Connection Parameters Request procedure\n         *\n         * If it was not possible to initiate the procedure, the function returns false.\n         */\n        bool initiating_connection_parameter_request( std::uint16_t interval_min, std::uint16_t interval_max, std::uint16_t latency, std::uint16_t timeout );\n\n        /**\n         * @brief initiates a PHY Update Procedure to request to upgrade the PHY to 2MBit.\n         *\n         * The update procedure is started as soon as possible.\n         */\n        bool phy_update_request_to_2mbit();\n\n        /**\n         * @brief initiates a PHY Update Procedure to the requested PHYs\n         * The update procedure is started as soon as possible.\n         */\n        bool phy_update_request( std::uint8_t transmit, std::uint8_t receive );\n\n        /**\n         * @brief initiate a remote version request\n         * @todo Add parameter that identifies the connection.\n         */\n        bool remote_versions_request();\n\n        /**\n         * @brief terminates the give connection\n         *\n         * @todo Add parameter that identifies the connection.\n         */\n        void disconnect();\n\n        /**\n         * @brief overload, that allows to specifiy the reason for disconnecting\n         */\n        void disconnect( std::uint8_t reason );\n\n        /**\n         * @brief fills the given buffer with l2cap advertising payload\n         */\n        std::size_t fill_l2cap_advertising_data( std::uint8_t* buffer, std::size_t buffer_size ) const;\n\n        /**\n         * @brief fills the given buffer with l2cap scan response payload\n         */\n        std::size_t fill_l2cap_scan_response_data( std::uint8_t* buffer, std::size_t buffer_size ) const;\n\n        /**\n         * @brief returns true, if advertising or scan response data might have changed.\n         */\n        bool l2cap_adverting_data_or_scan_response_data_changed();\n\n        /**\n         * @brief returns the feature mask of supported link layer features\n         */\n        std::uint64_t supported_link_layer_features() const;\n\n        /**\n         * @brief returns the Version field of the LL_VERSION_IND PDU\n         */\n        std::uint8_t supported_link_layer_version() const;\n\n        /**\n         * @brief returns the Company_Identifier field of the LL_VERSION_IND PDU\n         */\n        std::uint16_t link_layer_company_identifier() const;\n\n        /**\n         * @brief returns the own local device address\n         */\n        const device_address& local_address() const;\n\n        /**\n         * @brief set the local address\n         *\n         * The prefered method to define the address of the device is still through the\n         * use of bluetoe::link_layer::static_address. This function is intendet to be\n         * used, if the device has to change it's address at runtime.\n         */\n        void local_address( const device_address& new_address );\n\n        /** @cond HIDDEN_SYMBOLS */\n        using radio_t = ScheduledRadio<\n                details::buffer_sizes< Options... >::tx_size,\n                details::buffer_sizes< Options... >::rx_size,\n                link_layer< Server, ScheduledRadio, Options... >\n        >;\n\n        using layout_t = typename pdu_layout_by_radio< radio_t >::pdu_layout;\n        using l2cap_t  = typename details::l2cap_layer< Server, ScheduledRadio, Options... >::impl;\n\n        // Data associate with a established connection (beside LL parameters), like key, ATT MTU etc.\n        using connection_data_t = typename l2cap_t::connection_data_t;\n\n        // used by the l2cap layer to queue notifications / indications\n        static bool queue_lcap_notification( const ::bluetoe::details::notification_data& item, void* usr_arg, ::bluetoe::details::notification_type type );\n\n        // Allocate size bytes of L2CAP layer payload\n        std::pair< std::size_t, std::uint8_t* > allocate_l2cap_output_buffer( std::size_t size );\n        void commit_l2cap_output_buffer( std::pair< std::size_t, std::uint8_t* > buffer );\n\n        // will cause the link layer to inform the user callbacks that a connection event happend\n        void restart_user_timer();\n\n        /** @endcond */\n\n    private:\n\n        friend details::select_link_layer_security_impl< Server, link_layer< Server, ScheduledRadio, Options... > >;\n        friend details::select_phy_update_impl< ScheduledRadio<\n                details::buffer_sizes< Options... >::tx_size,\n                details::buffer_sizes< Options... >::rx_size,\n                link_layer< Server, ScheduledRadio, Options... >\n            > >;\n\n        static_assert(\n            std::is_same<\n                typename ::bluetoe::details::find_by_not_meta_type<\n                    details::valid_link_layer_option_meta_type,\n                    Options...\n                >::type, ::bluetoe::details::no_such_type >::value,\n            \"Option passed to the link layer, that is not a valid link_layer option.\" );\n\n        // make sure, that the hardware supports encryption\n        static constexpr bool encryption_required = bluetoe::details::requires_encryption_support_t< Server >::value;\n        static_assert( !encryption_required || ( encryption_required && radio_t::hardware_supports_encryption ),\n            \"The GATT server requires encryption while the selecte hardware binding doesn't provide support for encryption!\" );\n\n        using security_manager_t = typename details::security_manager<\n                link_layer< Server, ScheduledRadio, Options... >,\n                Server, Options...\n            >::type;\n\n        using signaling_channel_t = typename details::signaling_channel< Options... >::type;\n\n        using advertising_t = details::select_advertiser_implementation<\n            link_layer< Server, ScheduledRadio, Options... >, Options... >;\n\n        unsigned sleep_clock_accuracy( const std::uint8_t* received_body ) const;\n        bool check_timing_paremeters() const;\n        bool parse_timing_parameters_from_connect_request( const std::uint8_t* valid_connect_request_body );\n        bool parse_timing_parameters_from_connection_update_request( const std::uint8_t* valid_connect_request );\n        void force_disconnect();\n        void force_disconnect( std::uint8_t new_reason );\n        void start_advertising_impl();\n        delta_time setup_next_connection_event();\n        void transmit_pending_control_pdus();\n        void reject( std::uint8_t opcode, std::uint8_t error_code, read_buffer& output );\n\n        enum class ll_result {\n            go_ahead,\n            disconnect\n        };\n\n        ll_result handle_received_data();\n        ll_result send_control_pdus();\n        ll_result handle_ll_control_data( const write_buffer& pdu, read_buffer output );\n        // TODO Make handle_pending_ll_control() impossible to fail by checking PDUs immediately\n        ll_result handle_pending_ll_control( std::uint16_t instance );\n\n        connection_details details() const;\n\n        static constexpr unsigned       first_advertising_channel   = 37;\n        static constexpr unsigned       num_windows_til_timeout     = 6;\n        static constexpr auto           us_per_digits               = 1250;\n\n        static constexpr std::uint8_t   ll_control_pdu_code         = 3;\n        static constexpr std::uint8_t   lld_data_pdu_code           = 2;\n\n        static constexpr std::uint8_t   LL_CONNECTION_UPDATE_IND    = 0x00;\n        static constexpr std::uint8_t   LL_CHANNEL_MAP_REQ          = 0x01;\n        static constexpr std::uint8_t   LL_TERMINATE_IND            = 0x02;\n        static constexpr std::uint8_t   LL_ENC_REQ                  = 0x03;\n        static constexpr std::uint8_t   LL_ENC_RSP                  = 0x04;\n        static constexpr std::uint8_t   LL_START_ENC_REQ            = 0x05;\n        static constexpr std::uint8_t   LL_START_ENC_RSP            = 0x06;\n        static constexpr std::uint8_t   LL_UNKNOWN_RSP              = 0x07;\n        static constexpr std::uint8_t   LL_FEATURE_REQ              = 0x08;\n        static constexpr std::uint8_t   LL_FEATURE_RSP              = 0x09;\n        static constexpr std::uint8_t   LL_PAUSE_ENC_REQ            = 0x0A;\n        static constexpr std::uint8_t   LL_PAUSE_ENC_RSP            = 0x0B;\n        static constexpr std::uint8_t   LL_VERSION_IND              = 0x0C;\n        static constexpr std::uint8_t   LL_REJECT_IND               = 0x0D;\n        static constexpr std::uint8_t   LL_CONNECTION_PARAM_REQ     = 0x0F;\n        static constexpr std::uint8_t   LL_CONNECTION_PARAM_RSP     = 0x10;\n        static constexpr std::uint8_t   LL_REJECT_EXT_IND           = 0x11;\n        static constexpr std::uint8_t   LL_PING_REQ                 = 0x12;\n        static constexpr std::uint8_t   LL_PING_RSP                 = 0x13;\n        static constexpr std::uint8_t   LL_PHY_REQ                  = 0x16;\n        static constexpr std::uint8_t   LL_PHY_RSP                  = 0x17;\n        static constexpr std::uint8_t   LL_PHY_UPDATE_IND           = 0x18;\n\n        static constexpr std::uint8_t   LL_VERSION_NR               = 0x09;\n        static constexpr std::uint8_t   LL_VERSION_40               = 0x06;\n\n        static constexpr std::uint8_t   err_pin_or_key_missing      = 0x06;\n        static constexpr std::uint16_t  company_identifier          = 0x0269;\n\n        static constexpr std::uint8_t   connection_timeout          = 0x08;\n        static constexpr std::uint8_t   connection_terminated_by_local_host = 0x16;\n        static constexpr std::uint8_t   connection_ll_response_timeout = 0x22;\n        static constexpr std::uint8_t   connection_instant_passed   = 0x28;\n\n        static constexpr std::uint32_t  default_procedure_timeout_us= 40 * 1000 * 1000;\n\n        struct link_layer_feature {\n            enum : std::uint16_t {\n                le_encryption                           = 0x001,\n                connection_parameters_request_procedure = 0x002,\n                extended_reject_indication              = 0x004,\n                peripheral_initiated_features_exchange  = 0x008,\n                le_ping                                 = 0x010,\n                le_data_packet_length_extension         = 0x020,\n                ll_privacy                              = 0x040,\n                extended_scanner_filter_policies        = 0x080,\n                le_2m_phy_support                       = 0x100\n            };\n        };\n\n        static constexpr std::uint16_t   supported_features =\n            link_layer_feature::connection_parameters_request_procedure |\n            link_layer_feature::extended_reject_indication |\n            link_layer_feature::le_ping |\n            ( bluetoe::details::requires_encryption_support_t< Server >::value\n                ? link_layer_feature::le_encryption\n                : 0 ) |\n            ( radio_t::hardware_supports_2mbit\n                ? link_layer_feature::le_2m_phy_support\n                : 0 );\n\n        // TODO: calculate the actual needed buffer size for advertising, not the maximum\n        static_assert( radio_t::size >= advertising_t::maximum_required_advertising_buffer(), \"buffer to small\" );\n\n        // TODO: calculate the maximum required LL buffer size based on the supported features\n        static constexpr std::size_t    maximum_ll_payload_size = 27u;\n\n        device_address                  address_;\n        channel_map                     channels_;\n        unsigned                        cumulated_sleep_clock_accuracy_;\n        delta_time                      transmit_window_offset_;\n        delta_time                      transmit_window_size_;\n        delta_time                      connection_interval_;\n        std::uint16_t                   peripheral_latency_;\n        std::uint16_t                   timeout_value_;\n        delta_time                      connection_timeout_;\n        delta_time                      procedure_timeout_;\n        std::uint16_t                   defered_conn_event_counter_;\n        write_buffer                    defered_ll_control_pdu_;\n        connection_data_t               connection_data_;\n        bool                            termination_send_;\n        std::uint16_t                   used_features_;\n        bool                            pending_event_;\n        volatile bool                   restart_user_timer_requested_;\n        std::uint8_t                    disconnecting_reason_;\n\n        enum class state\n        {\n            initial,\n            advertising,\n            connecting,\n            connected,\n            disconnecting,\n            connection_changed\n        }                               state_;\n\n        std::uint16_t                   proposed_interval_min_;\n        std::uint16_t                   proposed_interval_max_;\n        std::uint16_t                   proposed_latency_;\n        std::uint16_t                   proposed_timeout_;\n        bool                            connection_parameters_request_pending_;\n        bool                            connection_parameters_request_running_;\n        bool                            connection_parameters_request_use_signaling_channel_;\n        bool                            phy_update_request_pending_;\n        std::uint8_t                    phy_update_request_transmit_;\n        std::uint8_t                    phy_update_request_receive_;\n        bool                            remote_versions_request_pending_;\n        bool                            version_indication_received_;\n\n        // default configuration parameters\n        typedef                         advertising_interval< 100 >         default_advertising_interval;\n        typedef                         sleep_clock_accuracy_ppm< 500 >     default_sleep_clock_accuracy;\n        typedef                         random_static_address               default_device_address;\n\n        typedef typename ::bluetoe::details::find_by_meta_type<\n            details::device_address_meta_type,\n            Options..., default_device_address >::type              local_device_address;\n\n        typedef typename ::bluetoe::details::find_by_meta_type<\n            details::sleep_clock_accuracy_meta_type,\n            Options..., default_sleep_clock_accuracy >::type        device_sleep_clock_accuracy;\n\n        typedef typename ::bluetoe::details::find_by_meta_type<\n            details::connection_event_callback_meta_type,\n            Options..., details::default_connection_event_callback\n        >::type                                                     connection_event_callback;\n    };\n\n    // implementation\n    /** @cond HIDDEN_SYMBOLS */\n    template < class Server, template < std::size_t, std::size_t, class > class ScheduledRadio, typename ... Options >\n    link_layer< Server, ScheduledRadio, Options... >::link_layer()\n        : address_( local_device_address::address( *this ) )\n        , defered_ll_control_pdu_{ nullptr, 0 }\n        , used_features_( supported_features )\n        , restart_user_timer_requested_( false )\n        , state_( state::initial )\n        , connection_parameters_request_pending_( false )\n        , connection_parameters_request_running_( false )\n        , phy_update_request_pending_( false )\n        , remote_versions_request_pending_( false )\n        , version_indication_received_( false )\n    {\n        using user_timer_t = typename bluetoe::details::find_by_meta_type<\n            details::synchronized_connection_event_callback_meta_type,\n            Options...,\n            no_synchronized_connection_event_callback\n        >::type;\n\n        using compile_time_check_user_timer_parameters_t = typename ::bluetoe::details::find_by_meta_type<\n            details::check_synchronized_connection_event_callback_meta_type,\n            Options..., no_check_synchronized_connection_event_callback\n        >::type;\n\n        compile_time_check_user_timer_parameters_t::template check< link_layer< Server, ScheduledRadio, Options... > >( user_timer_t() );\n\n        this->notification_callback( queue_lcap_notification, this );\n    }\n\n    template < class Server, template < std::size_t, std::size_t, class > class ScheduledRadio, typename ... Options >\n    void link_layer< Server, ScheduledRadio, Options... >::run()\n    {\n        // after the initial scheduling, the timeout and receive callback will setup the next scheduling\n        if ( state_ == state::initial )\n        {\n            start_advertising_impl();\n        }\n\n        radio_t::run();\n    }\n\n    template < class Server, template < std::size_t, std::size_t, class > class ScheduledRadio, typename ... Options >\n    void link_layer< Server, ScheduledRadio, Options... >::adv_received( const read_buffer& receive )\n    {\n        using namespace ::bluetoe::details;\n\n        assert( state_ == state::advertising );\n\n        device_address remote_address;\n        const bool connection_request_received = this->handle_adv_receive( receive, remote_address );\n\n        if ( connection_request_received )\n        {\n            const std::uint8_t* const body = layout_t::body( receive ).first;\n\n            if ( channels_.reset( &body[ 28 ], body[ 33 ] & 0x1f )\n              && parse_timing_parameters_from_connect_request( body ) )\n            {\n                this->reset_connection_state();\n\n                state_                                  = state::connecting;\n                cumulated_sleep_clock_accuracy_         = sleep_clock_accuracy( body ) + device_sleep_clock_accuracy::accuracy_ppm;\n                used_features_                          = supported_features;\n                connection_parameters_request_pending_  = false;\n                connection_parameters_request_running_  = false;\n                connection_parameters_request_use_signaling_channel_ = false;\n                phy_update_request_pending_             = false;\n                pending_event_                          = false;\n                remote_versions_request_pending_        = false;\n                version_indication_received_            = false;\n                disconnecting_reason_                   = connection_timeout;\n                procedure_timeout_                      = delta_time();\n\n                this->set_access_address_and_crc_init( read_32bit( &body[ 12 ] ), read_24bit( &body[ 16 ] ) );\n\n                this->reset_pdu_buffer();\n                this->reset_connection_parameter_request();\n                setup_next_connection_event();\n\n                this->connection_request( connection_addresses( address_, remote_address ) );\n                this->handle_stop_advertising();\n\n                connection_data_ = connection_data_t();\n                connection_data_.remote_connection_created( remote_address );\n                this->connection_requested( details(), connection_data_, static_cast< radio_t& >( *this ) );\n                this->template handle_connection_events< link_layer< Server, ScheduledRadio, Options... > >();\n            }\n        }\n    }\n\n    template < class Server, template < std::size_t, std::size_t, class > class ScheduledRadio, typename ... Options >\n    void link_layer< Server, ScheduledRadio, Options... >::adv_timeout()\n    {\n        assert( state_ == state::advertising );\n\n        this->handle_adv_timeout();\n    }\n\n    template < class Server, template < std::size_t, std::size_t, class > class ScheduledRadio, typename ... Options >\n    void link_layer< Server, ScheduledRadio, Options... >::timeout()\n    {\n        pending_event_ = false;\n\n        assert( state_ == state::connecting || state_ == state::connected || state_ == state::disconnecting || state_ == state::connection_changed );\n\n        const auto time_since_last_event = this->time_since_last_event();\n\n        if ( state_ == state::disconnecting && termination_send_ && !this->pending_outgoing_data_available() )\n        {\n            force_disconnect();\n        }\n        else if ( !procedure_timeout_.zero() && procedure_timeout_ <= time_since_last_event )\n        {\n            force_disconnect( connection_ll_response_timeout );\n        }\n        else if ( time_since_last_event < connection_timeout_\n            && !( state_ == state::connecting && time_since_last_event >= ( num_windows_til_timeout - 1 ) * connection_interval_ ) )\n        {\n            this->plan_next_connection_event_after_timeout( connection_interval_ );\n\n            if ( handle_pending_ll_control( this->connection_event_counter() ) == ll_result::disconnect )\n            {\n                force_disconnect();\n            }\n            else\n            {\n                setup_next_connection_event();\n            }\n        }\n        else\n        {\n            force_disconnect();\n        }\n\n        this->template handle_connection_events< link_layer< Server, ScheduledRadio, Options... > >();\n    }\n\n    template < class Server, template < std::size_t, std::size_t, class > class ScheduledRadio, typename ... Options >\n    void link_layer< Server, ScheduledRadio, Options... >::end_event( connection_event_events evts )\n    {\n        pending_event_ = false;\n\n        assert( state_ == state::connecting || state_ == state::connected || state_ == state::disconnecting || state_ == state::connection_changed );\n\n        if ( state_ == state::connecting || restart_user_timer_requested_ )\n        {\n            this->synchronized_connection_event_callback_new_connection( connection_interval_ );\n            restart_user_timer_requested_ = false;\n        }\n\n        if ( state_ == state::connecting )\n        {\n            this->connection_established( details(), connection_data_, static_cast< radio_t& >( *this ) );\n        }\n        else if ( state_ == state::connection_changed )\n        {\n            this->synchronized_connection_event_callback_connection_changed( connection_interval_ );\n        }\n\n        if ( state_ != state::disconnecting )\n        {\n            state_                = state::connected;\n            transmit_window_size_ = delta_time();\n        }\n\n        /*\n         * L2CAP and pending LL PDUs are handle first, to get the information whether there is\n         * data to be send. This implies that the connEventCount is not updated at this point\n         * and has to be offset by 1 to see if there is a pending instant at this connection\n         * event.\n         */\n        if ( ( state_ == state::disconnecting && termination_send_ && !this->pending_outgoing_data_available() )\n          || handle_received_data() == ll_result::disconnect\n          || send_control_pdus() == ll_result::disconnect )\n        {\n            force_disconnect();\n        }\n        else\n        {\n            const auto time_since_last_event = this->time_since_last_event();\n            const bool procedure_timed_out = !procedure_timeout_.zero() && procedure_timeout_ <= time_since_last_event;\n\n            if ( !procedure_timeout_.zero() && !procedure_timed_out )\n                procedure_timeout_ -= time_since_last_event;\n\n            if ( procedure_timed_out )\n            {\n                force_disconnect( connection_ll_response_timeout );\n            }\n            else\n            {\n                this->transmit_pending_security_pdus();\n\n                const std::pair< bool, std::uint16_t > pending_instant = { !defered_ll_control_pdu_.empty(), defered_conn_event_counter_ };\n\n                evts.pending_outgoing_data = evts.pending_outgoing_data || this->pending_outgoing_data_available();\n                this->plan_next_connection_event(\n                    peripheral_latency_, evts, connection_interval_, pending_instant );\n\n                // Handle pending LL control PDUs that will affect the _next_ connection event\n                if ( handle_pending_ll_control( this->connection_event_counter() ) == ll_result::disconnect )\n                {\n                    force_disconnect();\n                }\n                else\n                {\n                    const delta_time time_till_next_event = setup_next_connection_event();\n                    connection_event_callback::call_connection_event_callback( time_till_next_event );\n                }\n            }\n        }\n\n        if ( state_ == state::connected || state_ == state::connecting )\n        {\n            transmit_pending_control_pdus();\n            this->transmit_pending_l2cap_output( connection_data_ );\n        }\n\n        this->template handle_connection_events< link_layer< Server, ScheduledRadio, Options... > >();\n    }\n\n    template < class Server, template < std::size_t, std::size_t, class > class ScheduledRadio, typename ... Options >\n    void link_layer< Server, ScheduledRadio, Options... >::restart_user_timer()\n    {\n        restart_user_timer_requested_ = true;\n    }\n\n    template < class Server, template < std::size_t, std::size_t, class > class ScheduledRadio, typename ... Options >\n    void link_layer< Server, ScheduledRadio, Options... >::user_timer( bool anchor_moved )\n    {\n        this->synchronized_connection_event_callback_timeout( anchor_moved );\n    }\n\n    template < class Server, template < std::size_t, std::size_t, class > class ScheduledRadio, typename ... Options >\n    void link_layer< Server, ScheduledRadio, Options... >::try_event_cancelation()\n    {\n        if ( ( state_ == state::connected || state_ == state::connecting )\n          && pending_event_ && this->reschedule_on_pending_data( *this, connection_interval_ ) )\n        {\n            setup_next_connection_event();\n        }\n    }\n\n    template < class Server, template < std::size_t, std::size_t, class > class ScheduledRadio, typename ... Options >\n    bool link_layer< Server, ScheduledRadio, Options... >::connection_parameter_update_request( std::uint16_t interval_min, std::uint16_t interval_max, std::uint16_t latency, std::uint16_t timeout )\n    {\n        if ( used_features_ & link_layer_feature::connection_parameters_request_procedure )\n        {\n            if ( connection_parameters_request_pending_ )\n                return false;\n\n            proposed_interval_min_  = interval_min;\n            proposed_interval_max_  = interval_max;\n            proposed_latency_       = latency;\n            proposed_timeout_       = timeout;\n            connection_parameters_request_pending_ = true;\n            connection_parameters_request_use_signaling_channel_ = true;\n\n            this->wake_up();\n\n            return true;\n        }\n\n        const bool result = static_cast< signaling_channel_t& >( *this ).connection_parameter_update_request( interval_min, interval_max, latency, timeout );\n\n        if ( result )\n            this->wake_up();\n\n        return result;\n    }\n\n    template < class Server, template < std::size_t, std::size_t, class > class ScheduledRadio, typename ... Options >\n    bool link_layer< Server, ScheduledRadio, Options... >::initiating_connection_parameter_request( std::uint16_t interval_min, std::uint16_t interval_max, std::uint16_t latency, std::uint16_t timeout )\n    {\n        if ( connection_parameters_request_pending_ || !procedure_timeout_.zero() )\n            return false;\n\n        proposed_interval_min_  = interval_min;\n        proposed_interval_max_  = interval_max;\n        proposed_latency_       = latency;\n        proposed_timeout_       = timeout;\n        connection_parameters_request_pending_ = true;\n\n        this->wake_up();\n\n        return true;\n    }\n\n    template < class Server, template < std::size_t, std::size_t, class > class ScheduledRadio, typename ... Options >\n    bool link_layer< Server, ScheduledRadio, Options... >::phy_update_request_to_2mbit()\n    {\n        return phy_update_request(\n            phy_ll_encoding::phy_ll_encoding_t::le_2m_phy,\n            phy_ll_encoding::phy_ll_encoding_t::le_2m_phy );\n    }\n\n    template < class Server, template < std::size_t, std::size_t, class > class ScheduledRadio, typename ... Options >\n    bool link_layer< Server, ScheduledRadio, Options... >::phy_update_request( std::uint8_t transmit, std::uint8_t receive )\n    {\n        if ( phy_update_request_pending_ )\n            return false;\n\n        phy_update_request_pending_  = true;\n        phy_update_request_transmit_ = transmit;\n        phy_update_request_receive_  = receive;\n        this->wake_up();\n\n        return true;\n    }\n\n    template < class Server, template < std::size_t, std::size_t, class > class ScheduledRadio, typename ... Options >\n    bool link_layer< Server, ScheduledRadio, Options... >::remote_versions_request()\n    {\n        if ( remote_versions_request_pending_ || !procedure_timeout_.zero() )\n            return false;\n\n        remote_versions_request_pending_ = true;\n        this->wake_up();\n\n        return true;\n    }\n\n    template < class Server, template < std::size_t, std::size_t, class > class ScheduledRadio, typename ... Options >\n    void link_layer< Server, ScheduledRadio, Options... >::disconnect()\n    {\n        disconnect( connection_terminated_by_local_host );\n    }\n\n    template < class Server, template < std::size_t, std::size_t, class > class ScheduledRadio, typename ... Options >\n    void link_layer< Server, ScheduledRadio, Options... >::disconnect( std::uint8_t reason )\n    {\n        state_                = state::disconnecting;\n        termination_send_     = false;\n        disconnecting_reason_ = reason;\n        procedure_timeout_    = connection_timeout_;\n\n        this->synchronized_connection_event_callback_disconnect();\n        this->reset_encryption();\n    }\n\n    template < class Server, template < std::size_t, std::size_t, class > class ScheduledRadio, typename ... Options >\n    delta_time link_layer< Server, ScheduledRadio, Options... >::setup_next_connection_event()\n    {\n        pending_event_ = true;\n\n        delta_time window_start;\n        delta_time window_end;\n\n        const delta_time time_since_last_event = this->time_since_last_event();\n\n        // optimization to calculate the deviation only once for the symetrical case\n        if ( !transmit_window_size_.zero() )\n        {\n            window_start = time_since_last_event + transmit_window_offset_;\n            window_end   = window_start + transmit_window_size_;\n\n            window_start -= window_start.ppm( cumulated_sleep_clock_accuracy_ );\n            window_end   += window_end.ppm( cumulated_sleep_clock_accuracy_ );\n        }\n        else\n        {\n            const delta_time window_size   = time_since_last_event.ppm( cumulated_sleep_clock_accuracy_ );\n\n            window_start  = time_since_last_event - window_size;\n            window_end    = time_since_last_event + window_size;\n        }\n\n        return this->schedule_connection_event(\n                channels_.data_channel( this->current_channel_index() ),\n                window_start,\n                window_end,\n                connection_interval_ );\n    }\n\n    template < class Server, template < std::size_t, std::size_t, class > class ScheduledRadio, typename ... Options >\n    void link_layer< Server, ScheduledRadio, Options... >::transmit_pending_control_pdus()\n    {\n        static constexpr std::uint8_t connection_param_req_size = 24u;\n\n        if ( !connection_parameters_request_pending_\n          && !phy_update_request_pending_\n          && !remote_versions_request_pending_\n          && !this->connection_parameters_response_pending() )\n            return;\n\n        // first check if we have memory to transmit the message, or otherwise notifications would get lost\n        auto out_buffer = this->allocate_ll_transmit_buffer( connection_param_req_size );\n\n        if ( out_buffer.empty() )\n        {\n            this->wake_up();\n            return;\n        }\n\n        if ( connection_parameters_request_pending_ )\n        {\n            procedure_timeout_ = delta_time( default_procedure_timeout_us );\n            connection_parameters_request_pending_ = false;\n            connection_parameters_request_running_ = true;\n\n            fill< layout_t >( out_buffer, {\n                ll_control_pdu_code, connection_param_req_size, LL_CONNECTION_PARAM_REQ,\n                static_cast< std::uint8_t >( proposed_interval_min_ ),\n                static_cast< std::uint8_t >( proposed_interval_min_ >> 8 ),\n                static_cast< std::uint8_t >( proposed_interval_max_ ),\n                static_cast< std::uint8_t >( proposed_interval_max_ >> 8 ),\n                static_cast< std::uint8_t >( proposed_latency_ ),\n                static_cast< std::uint8_t >( proposed_latency_ >> 8 ),\n                static_cast< std::uint8_t >( proposed_timeout_ ),\n                static_cast< std::uint8_t >( proposed_timeout_ >> 8 ),\n                0x00,                                   // PreferredPeriodicity (none)\n                0x00, 0x00,                             // ReferenceConnEventCount\n                0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\n                0xff, 0xff, 0xff, 0xff, 0xff, 0xff } );\n\n            this->commit_ll_transmit_buffer( out_buffer );\n        }\n        else if ( phy_update_request_pending_ )\n        {\n            phy_update_request_pending_ = false;\n\n            fill< layout_t >( out_buffer, {\n                ll_control_pdu_code, 3, LL_PHY_REQ,\n                phy_update_request_transmit_, phy_update_request_receive_ } );\n\n            this->commit_ll_transmit_buffer( out_buffer );\n        }\n        else if ( remote_versions_request_pending_ )\n        {\n            procedure_timeout_ = delta_time( default_procedure_timeout_us );\n            remote_versions_request_pending_ = false;\n\n            fill< layout_t >( out_buffer, {\n                ll_control_pdu_code, 6, LL_VERSION_IND,\n                LL_VERSION_NR,\n                static_cast< std::uint8_t >( company_identifier ),\n                static_cast< std::uint8_t >( company_identifier >> 8 ),\n                0x00, 0x00\n            } );\n\n            this->commit_ll_transmit_buffer( out_buffer );\n        }\n        else if ( this->connection_parameters_response_pending() )\n        {\n            this->template connection_parameters_response_fill< layout_t >( out_buffer );\n            this->commit_ll_transmit_buffer( out_buffer );\n        }\n    }\n\n    template < class Server, template < std::size_t, std::size_t, class > class ScheduledRadio, typename ... Options >\n    void link_layer< Server, ScheduledRadio, Options... >::reject( std::uint8_t opcode, std::uint8_t error_code, read_buffer& output )\n    {\n        if ( used_features_ & link_layer_feature::extended_reject_indication )\n        {\n            fill< layout_t >( output, {\n                ll_control_pdu_code, 3, LL_REJECT_EXT_IND, opcode, error_code } );\n        }\n        else\n        {\n            fill< layout_t >( output, {\n                ll_control_pdu_code, 2, LL_REJECT_IND, error_code } );\n        }\n    }\n\n    template < class Server, template < std::size_t, std::size_t, class > class ScheduledRadio, typename ... Options >\n    bool link_layer< Server, ScheduledRadio, Options... >::queue_lcap_notification( const ::bluetoe::details::notification_data& item, void* that, ::bluetoe::details::notification_type type )\n    {\n        auto& connection = static_cast< link_layer< Server, ScheduledRadio, Options... >* >( that )->connection_data_;\n\n        bool new_data = false;\n        // TODO: Synchronization required!!!\n        switch ( type )\n        {\n            case bluetoe::details::notification_type::notification:\n                new_data = connection.queue_notification( item.client_characteristic_configuration_index() );\n                break;\n            case bluetoe::details::notification_type::indication:\n                new_data = connection.queue_indication( item.client_characteristic_configuration_index() );\n                break;\n            case bluetoe::details::notification_type::confirmation:\n                connection.indication_confirmed();\n                return true;\n                break;\n        }\n\n        if ( new_data )\n            static_cast< link_layer< Server, ScheduledRadio, Options... >* >( that )->request_event_cancelation();\n\n        return new_data;\n    }\n\n    template < class Server, template < std::size_t, std::size_t, class > class ScheduledRadio, typename ... Options >\n    unsigned link_layer< Server, ScheduledRadio, Options... >::sleep_clock_accuracy( const std::uint8_t* received_body ) const\n    {\n        static constexpr std::uint16_t inaccuracy_ppm[ 8 ] = {\n            500, 250, 150, 100, 75, 50, 30, 20\n        };\n\n        return inaccuracy_ppm[ ( received_body[ 33 ] >> 5 & 0x7 )  ];\n    }\n\n    template < class Server, template < std::size_t, std::size_t, class > class ScheduledRadio, typename ... Options >\n    bool link_layer< Server, ScheduledRadio, Options... >::check_timing_paremeters() const\n    {\n        static constexpr delta_time maximum_transmit_window_offset( 10 * 1000 );\n        static constexpr delta_time maximum_connection_timeout( 32 * 1000 * 1000 );\n        static constexpr delta_time minimum_connection_timeout( 100 * 1000 );\n\n        return transmit_window_size_ <= maximum_transmit_window_offset\n            && transmit_window_size_ <= connection_interval_\n            && connection_timeout_ >= minimum_connection_timeout\n            && connection_timeout_ <= maximum_connection_timeout\n            && connection_timeout_ >= ( peripheral_latency_ + 1 ) * 2 * connection_interval_\n            && peripheral_latency_ <= maximum_link_layer_peripheral_latency;\n    }\n\n    template < class Server, template < std::size_t, std::size_t, class > class ScheduledRadio, typename ... Options >\n    bool link_layer< Server, ScheduledRadio, Options... >::parse_timing_parameters_from_connect_request( const std::uint8_t* valid_connect_request_body )\n    {\n        using namespace ::bluetoe::details;\n\n        const delta_time transmit_window_offset = delta_time( read_16bit( &valid_connect_request_body[ 20 ] ) * us_per_digits );\n\n        transmit_window_size_   = delta_time( valid_connect_request_body[ 19 ] * us_per_digits );\n        transmit_window_offset_ = delta_time( read_16bit( &valid_connect_request_body[ 20 ] ) * us_per_digits + us_per_digits );\n        connection_interval_    = delta_time( read_16bit( &valid_connect_request_body[ 22 ] ) * us_per_digits );\n        peripheral_latency_     = read_16bit( &valid_connect_request_body[ 24 ] );\n        timeout_value_          = read_16bit( &valid_connect_request_body[ 26 ] );\n        connection_timeout_     = delta_time( timeout_value_ * 10000 );\n\n        return transmit_window_offset <= connection_interval_ && check_timing_paremeters();\n    }\n\n    template < class Server, template < std::size_t, std::size_t, class > class ScheduledRadio, typename ... Options >\n    bool link_layer< Server, ScheduledRadio, Options... >::parse_timing_parameters_from_connection_update_request( const std::uint8_t* valid_update_request )\n    {\n        using namespace ::bluetoe::details;\n\n        transmit_window_size_   = delta_time( valid_update_request[ 1 ] * us_per_digits );\n        transmit_window_offset_ = delta_time( read_16bit( &valid_update_request[ 2 ] ) * us_per_digits );\n        connection_interval_    = delta_time( read_16bit( &valid_update_request[ 4 ] ) * us_per_digits );\n        peripheral_latency_     = read_16bit( &valid_update_request[ 6 ] );\n        timeout_value_          = read_16bit( &valid_update_request[ 8 ] );\n        connection_timeout_     = delta_time( timeout_value_ * 10000 );\n\n        return transmit_window_offset_ <= connection_interval_ && check_timing_paremeters();\n    }\n\n    template < class Server, template < std::size_t, std::size_t, class > class ScheduledRadio, typename ... Options >\n    void link_layer< Server, ScheduledRadio, Options... >::force_disconnect()\n    {\n        this->reset_encryption();\n        this->reset_phy( *this );\n\n        if ( state_ != state::connecting )\n        {\n            this->synchronized_connection_event_callback_disconnect();\n            this->connection_closed( disconnecting_reason_, connection_data_, static_cast< radio_t& >( *this ) );\n        }\n        else\n        {\n            this->connection_attempt_timeout( connection_data_, static_cast< radio_t& >( *this ) );\n        }\n\n        start_advertising_impl();\n    }\n\n    template < class Server, template < std::size_t, std::size_t, class > class ScheduledRadio, typename ... Options >\n    void link_layer< Server, ScheduledRadio, Options... >::force_disconnect( std::uint8_t new_reason )\n    {\n        disconnecting_reason_ = new_reason;\n        force_disconnect();\n    }\n\n    template < class Server, template < std::size_t, std::size_t, class > class ScheduledRadio, typename ... Options >\n    void link_layer< Server, ScheduledRadio, Options... >::start_advertising_impl()\n    {\n        state_ = state::advertising;\n\n        defered_ll_control_pdu_ = write_buffer{ nullptr, 0 };\n\n        this->handle_start_advertising();\n    }\n\n    template < class Server, template < std::size_t, std::size_t, class > class ScheduledRadio, typename ... Options >\n    typename link_layer< Server, ScheduledRadio, Options... >::ll_result link_layer< Server, ScheduledRadio, Options... >::handle_received_data()\n    {\n        ll_result result = ll_result::go_ahead;\n\n        if ( !defered_ll_control_pdu_.empty() )\n            return result;\n\n        for ( auto pdu = this->next_ll_l2cap_received(); pdu.size != 0 && result == ll_result::go_ahead && defered_ll_control_pdu_.empty(); )\n        {\n            const auto llid = layout_t::header( pdu ) & 0x03;\n            const auto body = layout_t::body( pdu );\n\n            if ( llid == ll_control_pdu_code )\n            {\n                const read_buffer output = this->allocate_ll_transmit_buffer( maximum_ll_payload_size );\n\n                if ( output.size )\n                {\n                    result = handle_ll_control_data( pdu, output );\n                    this->free_ll_l2cap_received();\n                    pdu = this->next_ll_l2cap_received();\n                }\n                else\n                {\n                    pdu.size = 0;\n                }\n            }\n            else if ( llid == lld_data_pdu_code && state_ != state::disconnecting\n                   && this->handle_l2cap_input( body.first, body.second - body.first, connection_data_ ) )\n            {\n                this->free_ll_l2cap_received();\n                pdu = this->next_ll_l2cap_received();\n            }\n            else\n            {\n                pdu.size = 0;\n            }\n        }\n\n        return result;\n    }\n\n    template < class Server, template < std::size_t, std::size_t, class > class ScheduledRadio, typename ... Options >\n    typename link_layer< Server, ScheduledRadio, Options... >::ll_result link_layer< Server, ScheduledRadio, Options... >::send_control_pdus()\n    {\n        if ( state_ == state::disconnecting && !termination_send_ )\n        {\n            auto output = this->allocate_ll_transmit_buffer( maximum_ll_payload_size );\n\n            if ( output.size )\n            {\n                fill< layout_t >( output, {\n                    ll_control_pdu_code, 2,\n                    LL_TERMINATE_IND, disconnecting_reason_\n                } );\n\n                this->commit_ll_transmit_buffer( output );\n                this->stop_ll_pdu_buffer();\n                termination_send_ = true;\n            }\n        }\n\n        return ll_result::go_ahead;\n    }\n\n    template < class Server, template < std::size_t, std::size_t, class > class ScheduledRadio, typename ... Options >\n    typename link_layer< Server, ScheduledRadio, Options... >::ll_result link_layer< Server, ScheduledRadio, Options... >::handle_ll_control_data( const write_buffer& pdu, read_buffer write )\n    {\n        using namespace ::bluetoe::details;\n\n        ll_result result = ll_result::go_ahead;\n        bool      commit = true;\n\n        assert( write.size >= radio_t::min_buffer_size );\n\n        const std::uint8_t* const body       = layout_t::body( pdu ).first;\n        const std::uint16_t       header     = layout_t::header( pdu );\n\n        if ( ( header & 0x3 ) == ll_control_pdu_code )\n        {\n            const std::uint8_t size   = header >> 8;\n            const std::uint8_t opcode = size > 0 ? *body : 0xff;\n\n            if ( opcode == LL_CONNECTION_UPDATE_IND && size == 12 )\n            {\n                defered_conn_event_counter_ = read_16bit( &body[ 10 ] );\n                commit = false;\n\n                if ( static_cast< std::uint16_t >( defered_conn_event_counter_ - this->connection_event_counter() + 1 ) & 0x8000\n                    || defered_conn_event_counter_ == this->connection_event_counter() + 1 )\n                {\n                    disconnecting_reason_ = connection_instant_passed;\n                    result = ll_result::disconnect;\n                }\n                else\n                {\n                    defered_ll_control_pdu_ = pdu;\n                }\n            }\n            else if ( opcode == LL_TERMINATE_IND && size == 2 )\n            {\n                disconnecting_reason_ = body[ 1 ];\n                commit = false;\n                result = ll_result::disconnect;\n            }\n            else if ( opcode == LL_VERSION_IND && size == 6 && !version_indication_received_ )\n            {\n                procedure_timeout_ = delta_time();\n\n                if ( body[ 1 ] <= LL_VERSION_40 )\n                    used_features_ = used_features_ & ~link_layer_feature::connection_parameters_request_procedure;\n\n                fill< layout_t >( write, {\n                    ll_control_pdu_code, 6, LL_VERSION_IND,\n                    LL_VERSION_NR,\n                    static_cast< std::uint8_t >( company_identifier ),\n                    static_cast< std::uint8_t >( company_identifier >> 8 ),\n                    0x00, 0x00\n                } );\n\n                this->version_indication_received( &body[ 1 ], connection_data_, static_cast< radio_t& >( *this ) );\n                version_indication_received_ = true;\n            }\n            else if ( opcode == LL_CHANNEL_MAP_REQ && size == 8 )\n            {\n                defered_conn_event_counter_ = read_16bit( &body[ 6 ] );\n                commit = false;\n\n                if ( static_cast< std::uint16_t >( defered_conn_event_counter_ - this->connection_event_counter() ) & 0x8000 )\n                {\n                    disconnecting_reason_ = connection_instant_passed;\n                    result = ll_result::disconnect;\n                }\n                else\n                {\n                    defered_ll_control_pdu_ = pdu;\n                }\n            }\n            else if ( opcode == LL_PING_REQ && size == 1 )\n            {\n                fill< layout_t >( write, { ll_control_pdu_code, 1, LL_PING_RSP } );\n            }\n            else if ( opcode == LL_FEATURE_REQ && size == 9 )\n            {\n                std::uint16_t remote_features = read_16bit( & body[ 1 ] );\n                used_features_ = used_features_ & remote_features;\n\n                // the LSB of the feature set has to be the actualy used set,\n                // while all remaining bytes are to be filled with the supported\n                // features\n                fill< layout_t >( write, {\n                    ll_control_pdu_code, 9,\n                    LL_FEATURE_RSP,\n                    static_cast< std::uint8_t >( used_features_ ),\n                    static_cast< std::uint8_t >( supported_features >> 8 ),\n                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00\n                } );\n\n                this->remote_features_received( &body[ 1 ], connection_data_, static_cast< radio_t& >( *this ) );\n            }\n            else if ( ( opcode == LL_UNKNOWN_RSP && size == 2 ) || ( opcode == LL_REJECT_IND && size == 2 ) || ( opcode == LL_REJECT_EXT_IND && size == 3 ) )\n            {\n                bool opcode_contains_request = opcode == LL_UNKNOWN_RSP || opcode == LL_REJECT_EXT_IND;\n\n                if ( !opcode_contains_request || ( opcode_contains_request && body[ 1 ] == LL_CONNECTION_PARAM_REQ ) )\n                {\n                    procedure_timeout_ = delta_time();\n\n                    if ( connection_parameters_request_running_ && connection_parameters_request_use_signaling_channel_ )\n                    {\n                        connection_parameters_request_use_signaling_channel_ = false;\n                        connection_parameters_request_running_ = false;\n\n                        if ( signaling_channel_t::connection_parameter_update_request(\n                            proposed_interval_min_,\n                            proposed_interval_max_,\n                            proposed_latency_,\n                            proposed_timeout_ ) )\n                        {\n                            this->wake_up();\n                        }\n                    }\n\n                    if ( opcode == LL_UNKNOWN_RSP )\n                        used_features_ = used_features_ & ~link_layer_feature::connection_parameters_request_procedure;\n                }\n\n                if ( opcode != LL_UNKNOWN_RSP )\n                {\n                    const std::uint8_t error_code = opcode == LL_REJECT_IND\n                        ? body[ 1 ]\n                        : body[ 2 ];\n\n                    this->procedure_rejected( error_code, connection_data_, static_cast< radio_t& >( *this ) );\n                }\n                else\n                {\n                    assert( opcode == LL_UNKNOWN_RSP );\n                    this->procedure_unknown( body[ 1 ], connection_data_, static_cast< radio_t& >( *this ) );\n                }\n\n                commit = false;\n            }\n            else if ( opcode == LL_CONNECTION_PARAM_REQ && size == 24 )\n            {\n                commit = this->template handle_connection_parameters_request< layout_t >( pdu, write, details() );\n            }\n            else if ( this->handle_encryption_pdus( opcode, size, pdu, write, commit ) )\n            {\n                // all encryption PDU handled in handle_encryption_pdus()\n            }\n            else if ( this->handle_phy_request( opcode, size, pdu, write, *this, commit ) )\n            {\n                // all phy PDU handled in handle_phy_reqest\n            }\n            else if ( opcode != LL_UNKNOWN_RSP )\n            {\n                fill< layout_t >( write, { ll_control_pdu_code, 2, LL_UNKNOWN_RSP, opcode } );\n            }\n            else\n            {\n                commit = false;\n            }\n\n            if ( commit )\n                this->commit_ll_transmit_buffer( write );\n        }\n\n        return result;\n    }\n\n    template < class Server, template < std::size_t, std::size_t, class > class ScheduledRadio, typename ... Options >\n    typename link_layer< Server, ScheduledRadio, Options... >::ll_result link_layer< Server, ScheduledRadio, Options... >::handle_pending_ll_control( std::uint16_t instance )\n    {\n        ll_result result = ll_result::go_ahead;\n\n        if ( !defered_ll_control_pdu_.empty() && defered_conn_event_counter_ == instance )\n        {\n            const std::uint8_t* body   = layout_t::body( defered_ll_control_pdu_ ).first;\n            const std::uint8_t  opcode = body[ 0 ];\n\n            if ( opcode == LL_CHANNEL_MAP_REQ )\n            {\n                channels_.reset( &body[ 1 ] );\n            }\n            else if ( opcode == LL_CONNECTION_UPDATE_IND )\n            {\n                procedure_timeout_ = delta_time();\n\n                if ( parse_timing_parameters_from_connection_update_request( body ) )\n                {\n                    state_ = state::connection_changed;\n                    this->synchronized_connection_event_callback_start_changing_connection();\n                    this->connection_changed( details(), connection_data_, static_cast< radio_t& >( *this ) );\n                }\n                else\n                {\n                    result = ll_result::disconnect;\n                }\n            }\n            else if ( this->handle_pending_phy_request( opcode, *this ) )\n            {\n            }\n            else\n            {\n                // This is an assert, as the opcode was already checked in handle_ll_control_data()\n                assert( !\"invalid opcode\" );\n            }\n\n            defered_ll_control_pdu_ = write_buffer{ nullptr, 0 };\n        }\n\n        return result;\n    }\n\n    template < class Server, template < std::size_t, std::size_t, class > class ScheduledRadio, typename ... Options >\n    connection_details link_layer< Server, ScheduledRadio, Options... >::details() const\n    {\n        return connection_details(\n            channels_,\n            connection_interval_.usec() / us_per_digits,\n            peripheral_latency_,\n            timeout_value_,\n            cumulated_sleep_clock_accuracy_ );\n    }\n\n    template < class Server, template < std::size_t, std::size_t, class > class ScheduledRadio, typename ... Options >\n    std::size_t link_layer< Server, ScheduledRadio, Options... >::fill_l2cap_advertising_data( std::uint8_t* buffer, std::size_t buffer_size ) const\n    {\n        return this->advertising_data( buffer, buffer_size );\n    }\n\n    template < class Server, template < std::size_t, std::size_t, class > class ScheduledRadio, typename ... Options >\n    std::size_t link_layer< Server, ScheduledRadio, Options... >::fill_l2cap_scan_response_data( std::uint8_t* buffer, std::size_t buffer_size ) const\n    {\n        return this->scan_response_data( buffer, buffer_size );\n    }\n\n    template < class Server, template < std::size_t, std::size_t, class > class ScheduledRadio, typename ... Options >\n    bool link_layer< Server, ScheduledRadio, Options... >::l2cap_adverting_data_or_scan_response_data_changed()\n    {\n        return this->advertising_or_scan_response_data_has_been_changed();\n    }\n\n    template < class Server, template < std::size_t, std::size_t, class > class ScheduledRadio, typename ... Options >\n    const device_address& link_layer< Server, ScheduledRadio, Options... >::local_address() const\n    {\n        return address_;\n    }\n\n    template < class Server, template < std::size_t, std::size_t, class > class ScheduledRadio, typename ... Options >\n    void link_layer< Server, ScheduledRadio, Options... >::local_address( const device_address& new_address )\n    {\n        address_ = new_address;\n    }\n\n    template < class Server, template < std::size_t, std::size_t, class > class ScheduledRadio, typename ... Options >\n    std::uint64_t link_layer< Server, ScheduledRadio, Options... >::supported_link_layer_features() const\n    {\n        return supported_features;\n    }\n\n    template < class Server, template < std::size_t, std::size_t, class > class ScheduledRadio, typename ... Options >\n    std::uint8_t link_layer< Server, ScheduledRadio, Options... >::supported_link_layer_version() const\n    {\n        return LL_VERSION_NR;\n    }\n\n    template < class Server, template < std::size_t, std::size_t, class > class ScheduledRadio, typename ... Options >\n    std::uint16_t link_layer< Server, ScheduledRadio, Options... >::link_layer_company_identifier() const\n    {\n        return company_identifier;\n    }\n\n    template < class Server, template < std::size_t, std::size_t, class > class ScheduledRadio, typename ... Options >\n    std::pair< std::size_t, std::uint8_t* > link_layer< Server, ScheduledRadio, Options... >::allocate_l2cap_output_buffer( std::size_t size )\n    {\n        const auto buffer = this->allocate_l2cap_transmit_buffer( size );\n\n        if ( buffer.size == 0 )\n            return { 0, nullptr };\n\n\n        const auto body      = layout_t::body( buffer );\n\n        return { body.second - body.first, body.first };\n    }\n\n    template < class Server, template < std::size_t, std::size_t, class > class ScheduledRadio, typename ... Options >\n    void link_layer< Server, ScheduledRadio, Options... >::commit_l2cap_output_buffer( std::pair< std::size_t, std::uint8_t* > buffer )\n    {\n        assert( buffer.first );\n        assert( buffer.second );\n\n        // TODO this type of calculations should be forwardet to the buffer\n        static constexpr std::size_t overhead = layout_t::data_channel_pdu_memory_size( 0 );\n\n        const read_buffer out_buffer{ buffer.second - overhead, buffer.first + overhead };\n\n        // TODO In case, that the buffer has to be fragmented, the header has to be rewritten\n        // by the buffer, so maybe better move that to the buffer too.\n        fill< layout_t >( out_buffer, {\n            lld_data_pdu_code,\n            static_cast< std::uint8_t >( buffer.first & 0xff ) } );\n\n        this->commit_l2cap_transmit_buffer( out_buffer );\n    }\n    /** @endcond */\n\n}\n}\n\n#endif\n"
  },
  {
    "path": "bluetoe/link_layer/include/bluetoe/ll_data_pdu_buffer.hpp",
    "content": "#ifndef BLUETOE_LINK_LAYER_LL_DAAT_BUFFER_HPP\n#define BLUETOE_LINK_LAYER_LL_DAAT_BUFFER_HPP\n\n#include <cstdlib>\n#include <cstdint>\n#include <cassert>\n#include <initializer_list>\n#include <algorithm>\n\n#include <bluetoe/default_pdu_layout.hpp>\n#include \"ring_buffer.hpp\"\n\nnamespace bluetoe {\nnamespace link_layer {\n\n    /**\n     * @brief ring buffers for ingoing and outgoing LL Data PDUs\n     *\n     * The buffer has two modes:\n     * - Stopped mode: In this mode, the internal buffer can be accessed\n     * - running mode: The buffer is used to communicate between the link layer and the scheduled radio\n     *\n     * The buffer has three interfaces:\n     * - one to access the transmit buffer from the link layer\n     * - one to access the receive buffer from the link layer\n     * - one to access the both buffers from the radio hardware\n     *\n     * This type is intendet to be inherited by the scheduled radio so that the\n     * ll_data_pdu_buffer can access the nessary radio interface by casting this to Radio*\n     * and to allow Radio to access the protected interface.\n     *\n     * TransmitSize and ReceiveSize are the total size of memory for the receiving and\n     * transmitting buffer. Depending on the layout of the used Radio, there might be\n     * an overhead per PDU.\n     */\n    template < std::size_t TransmitSize, std::size_t ReceiveSize, typename Radio >\n    class ll_data_pdu_buffer\n    {\n    public:\n        /**\n         * @post buffer is in stopped mode\n         */\n        ll_data_pdu_buffer();\n\n        /**\n         * @brief layout to be applied to each PDU.\n         *\n         * Basecally, this defined the overhead per PDU (layout_overhead).\n         */\n        using layout = typename pdu_layout_by_radio< Radio >::pdu_layout;\n\n        /**\n         * @brief the size of memory in bytes that are return by raw()\n         */\n        static constexpr std::size_t    size            = TransmitSize + ReceiveSize;\n\n        /**\n         * @brief the minimum size an element in the buffer can have (header size + payload size).\n         */\n        static constexpr std::size_t    min_buffer_size = 29;\n\n        /**\n         * @brief the maximum size an element in the buffer can have (header size + payload size).\n         */\n        static constexpr std::size_t    max_buffer_size = 251;\n\n        /**\n         * @brief 16 bit header size of a link layer PDU\n         */\n        static constexpr std::size_t    header_size     = 2u;\n\n        /**\n         * @brief addition layout overhead introduced by the applied layout\n         */\n        static constexpr std::size_t    layout_overhead = layout::data_channel_pdu_memory_size( 0 ) - header_size;\n\n        static_assert( TransmitSize >= layout_overhead + min_buffer_size,\n            \"TransmitSize should at least be large enough to store one L2CAP PDU plus overheader required by the hardware.\" );\n\n        static_assert( ReceiveSize >= layout_overhead + min_buffer_size,\n            \"ReceiveSize should at least be large enough to store one L2CAP PDU plus overheader required by the hardware.\" );\n\n        /**@{*/\n        /**\n         * @name buffer sizes\n         */\n\n        /**\n         * @brief returns the maximum value that can be used as maximum receive size.\n         *\n         * The result is equal to ReceiveSize.\n         */\n        constexpr std::size_t max_max_rx_size() const\n        {\n            return ReceiveSize - layout_overhead;\n        }\n\n        /**\n         * @brief the current maximum receive size\n         *\n         * No PDU with larger size can be receive. This will always return at least 29 plus the Radio's layout overhead.\n         */\n        std::size_t max_rx_size() const;\n\n        /**\n         * @brief set the maximum receive size\n         *\n         * The used size must be smaller or equal to ReceiveSize - layout_overhead / max_max_rx_size(), smaller than 251 and larger or equal to 29.\n         * The memory is best used, when ReceiveSize divided by max_size + layout_overhead results in an integer. That integer is\n         * then the number of PDUs that can be buffered on the receivin side.\n         *\n         * By default the function will return 29.\n         *\n         * @post max_rx_size() == max_size\n         */\n        void max_rx_size( std::size_t max_size );\n\n        /**\n         * @brief returns the maximum value that can be used as maximum receive size.\n         *\n         * The result is equal to TransmitSize.\n         */\n        constexpr std::size_t max_max_tx_size() const\n        {\n            return TransmitSize - ( layout::data_channel_pdu_memory_size( 0 ) - 2 );\n        }\n\n        /**\n         * @brief the current maximum transmit size\n         *\n         * No PDU with larger size can be transmitted. This will always return at least 29.\n         */\n        std::size_t max_tx_size() const;\n\n        /**\n         * @brief set the maximum transmit size\n         *\n         * The used size must be smaller or equal to TransmitSize / max_max_tx_size(), smaller than 251 and larger or equal to 29.\n         * The memory is best used, when TransmitSize divided by max_size results in an integer. That integer is\n         * then the number of PDUs that can be buffered on the transmitting side.\n         *\n         * By default the function will return 29.\n         *\n         * @post max_tx_size() == max_size\n         */\n        void max_tx_size( std::size_t max_size );\n\n        /**@}*/\n\n        /**@{*/\n        /**\n         * @name buffer modes\n         */\n\n        /**\n         * @brief returns the underlying raw buffer with a size of at least ll_data_pdu_buffer::size\n         *\n         * The underlying memory can be used when it's not used by other means. The size that can saftely be used is ll_data_pdu_buffer::size.\n         * @pre buffer is in stopped mode\n         */\n        std::uint8_t* raw_pdu_buffer();\n\n        /**\n         * @brief places the buffer in running mode.\n         *\n         * Receive and transmit buffers are empty. Sequence numbers are reseted.\n         * max_rx_size() is set to default\n         *\n         * @post next_received().empty()\n         * @post max_rx_size() == 29u\n         */\n        void reset_pdu_buffer();\n\n        /**\n         * @brief puts the buffer into stop mode\n         *\n         * In stop mode, the buffer will acknowledge received PDUs, but will ignore them.\n         * Every commited transmit buffer will be ignored. Unacknowledged outgoing data will\n         * be resend until acknowledged.\n         */\n        void stop_ll_pdu_buffer();\n\n        /**@}*/\n\n        /**@{*/\n        /**\n         * @name Interface to access the transmit buffers from the link layer\n         */\n\n        /**\n         * @brief allocates a certain amount of memory to place a PDU to be transmitted .\n         *\n         * If not enough memory is available, the function will return an empty buffer (size == 0).\n         * To indicate that the allocated memory is filled with data to be send, commit_transmit_buffer() must be called.\n         * The size parameter is the sum of the payload + header.\n         *\n         * @post r = allocate_transmit_buffer( n ); r.size == 0 || r.size == n\n         * @pre  buffer is in running mode\n         * @pre size <= max_tx_size()\n         */\n        read_buffer allocate_transmit_buffer( std::size_t size );\n\n        /**\n         * @brief calls allocate_transmit_buffer( max_tx_size() + layout_overhead );\n         */\n        read_buffer allocate_transmit_buffer();\n\n        /**\n         * @brief indicates that prior allocated memory is now ready for transmission\n         *\n         * To send a PDU, first allocate_transmit_buffer() have to be called, with the maximum size\n         * need to assemble the PDU. Then commit_transmit_buffer() have to be called with the\n         * size that the PDU is really filled with at the begining of the buffer.\n         *\n         * @pre a buffer must have been allocated by a call to allocate_transmit_buffer()\n         * @pre size\n         * @pre buffer is in running mode\n         */\n        void commit_transmit_buffer( read_buffer );\n\n        /**\n         * @brief returns true, if there is pending, outgoing data\n         */\n        bool pending_outgoing_data_available() const;\n\n        /**@}*/\n\n        /**@{*/\n        /**\n         * @name Interface to access the receive buffer from the link layer\n         */\n\n        /**\n         * @brief returns the oldest PDU out of the receive buffer.\n         *\n         * If there is no PDU in the receive buffer, an empty PDU will be returned (size == 0 ).\n         * The returned PDU is not removed from the buffer. To remove the buffer after it is\n         * not used any more, free_received() must be called.\n         *\n         * @pre buffer is in running mode\n         */\n        write_buffer next_received() const;\n\n        /**\n         * @brief removes the oldest PDU from the receive buffer.\n         * @pre next_received() was called without free_received() beeing called.\n         * @pre buffer is in running mode\n         */\n        void free_received();\n\n        /**@}*/\n\n    protected:\n        /**@{*/\n        /**\n         * @name Interface to the radio hardware\n         */\n\n        /**\n         * @brief allocates a buffer for the next PDU to be received.\n         *\n         * Once a buffer was allocated to the radio hardware is will be released by the hardware by calling\n         * received().\n         *\n         * This function can return an empty buffer if the receive buffers are all still allocated. The radio is\n         * than required to ignore all incoming trafic.\n         *\n         * @attention there should be a maximum of one allocated but jet not released buffer.\n         */\n        read_buffer allocate_receive_buffer() const;\n\n        /**\n         * @brief This function will be called by the scheduled radio when a PDU was received without error.\n         *\n         * The function returns the next buffer to be transmitted.\n         *\n         * This function will call increment_receive_packet_counter() and increment_transmit_packet_counter() on\n         * the Radio if the counter part of the encryption IV part have to be incremented.\n         */\n        write_buffer received( read_buffer );\n\n        /**\n         * @brief This function will be called, instead of received(), when the CRC of a received\n         *        PDU is ok, but the MIC is not ok.\n         *\n         * In this case, the MIC might not be ok, due to a PDU beeing resent. In this case, the\n         * the last send message can be acknowlaged, but the received PDU should not be queued in\n         * the buffer.\n         */\n        write_buffer acknowledge( read_buffer );\n\n        /**\n         * @brief returns the next PDU to be transmitted\n         *\n         * If the transmit buffer is empty, the function will return an empty PDU.\n         * @post next_transmit().size != 0 && next_transmit().buffer != nullptr\n         */\n        write_buffer next_transmit();\n        /**@}*/\n\n    private:\n        // transmit buffer followed by receive buffer at buffer_[ TransmitSize ]\n        std::uint8_t    buffer_[ size ];\n\n        pdu_ring_buffer< ReceiveSize, read_buffer, layout >  receive_buffer_;\n        volatile std::size_t            max_rx_size_;\n\n        pdu_ring_buffer< TransmitSize, read_buffer, layout > transmit_buffer_;\n        volatile std::size_t            max_tx_size_;\n\n        bool                    sequence_number_;\n        bool                    next_expected_sequence_number_;\n        uint8_t                 empty_[ layout::data_channel_pdu_memory_size( 0 ) ];\n        bool                    next_empty_;\n        bool                    empty_sequence_number_;\n        bool                    stopped_;\n\n        static constexpr std::size_t  ll_header_size = 2;\n        static constexpr std::uint8_t more_data_flag = 0x10;\n        static constexpr std::uint8_t sn_flag        = 0x8;\n        static constexpr std::uint8_t nesn_flag      = 0x4;\n        static constexpr std::uint8_t ll_empty_id    = 0x01;\n\n\n        const std::uint8_t* transmit_buffer() const\n        {\n            return &buffer_[ 0 ];\n        }\n\n        std::uint8_t* transmit_buffer()\n        {\n            return &buffer_[ 0 ];\n        }\n\n        const std::uint8_t* receive_buffer() const\n        {\n            return &buffer_[ TransmitSize ];\n        }\n\n        std::uint8_t* receive_buffer()\n        {\n            return &buffer_[ TransmitSize ];\n        }\n\n        write_buffer set_next_expected_sequence_number( read_buffer ) const;\n\n        void acknowledge( bool sequence_number );\n    };\n\n    // implementation\n    template < std::size_t TransmitSize, std::size_t ReceiveSize, typename Radio >\n    ll_data_pdu_buffer< TransmitSize, ReceiveSize, Radio >::ll_data_pdu_buffer()\n        : receive_buffer_( receive_buffer() )\n        , transmit_buffer_( transmit_buffer() )\n        , stopped_( false )\n    {\n        layout::header( empty_, 0 );\n        reset_pdu_buffer();\n    }\n\n    template < std::size_t TransmitSize, std::size_t ReceiveSize, typename Radio >\n    std::size_t ll_data_pdu_buffer< TransmitSize, ReceiveSize, Radio >::max_rx_size() const\n    {\n        return max_rx_size_;\n    }\n\n    template < std::size_t TransmitSize, std::size_t ReceiveSize, typename Radio >\n    void ll_data_pdu_buffer< TransmitSize, ReceiveSize, Radio >::max_rx_size( std::size_t max_size )\n    {\n        assert( max_size >= min_buffer_size );\n        assert( max_size <= max_buffer_size );\n        assert( max_size <= ReceiveSize - layout_overhead );\n\n        max_rx_size_ = max_size;\n    }\n\n    template < std::size_t TransmitSize, std::size_t ReceiveSize, typename Radio >\n    std::size_t ll_data_pdu_buffer< TransmitSize, ReceiveSize, Radio >::max_tx_size() const\n    {\n        return max_tx_size_;\n    }\n\n    template < std::size_t TransmitSize, std::size_t ReceiveSize, typename Radio >\n    void ll_data_pdu_buffer< TransmitSize, ReceiveSize, Radio >::max_tx_size( std::size_t max_size )\n    {\n        assert( max_size >= min_buffer_size );\n        assert( max_size <= max_buffer_size );\n        assert( max_size <= TransmitSize - layout_overhead );\n\n        max_tx_size_ = max_size;\n    }\n\n    template < std::size_t TransmitSize, std::size_t ReceiveSize, typename Radio >\n    void ll_data_pdu_buffer< TransmitSize, ReceiveSize, Radio >::reset_pdu_buffer()\n    {\n        max_rx_size_    = min_buffer_size;\n        receive_buffer_.reset( receive_buffer() );\n\n        max_tx_size_    = min_buffer_size;\n        transmit_buffer_.reset( transmit_buffer() );\n\n        sequence_number_ = false;\n        next_expected_sequence_number_ = false;\n        next_empty_      = false;\n        stopped_         = false;\n    }\n\n    template < std::size_t TransmitSize, std::size_t ReceiveSize, typename Radio >\n    void ll_data_pdu_buffer< TransmitSize, ReceiveSize, Radio >::stop_ll_pdu_buffer()\n    {\n        stopped_ = true;\n    }\n\n    template < std::size_t TransmitSize, std::size_t ReceiveSize, typename Radio >\n    std::uint8_t* ll_data_pdu_buffer< TransmitSize, ReceiveSize, Radio >::raw_pdu_buffer()\n    {\n        return &buffer_[ 0 ];\n    }\n\n    template < std::size_t TransmitSize, std::size_t ReceiveSize, typename Radio >\n    read_buffer ll_data_pdu_buffer< TransmitSize, ReceiveSize, Radio >::allocate_transmit_buffer( std::size_t size )\n    {\n        typename Radio::lock_guard lock;\n\n        return transmit_buffer_.alloc_front( transmit_buffer(), size );\n    }\n\n    template < std::size_t TransmitSize, std::size_t ReceiveSize, typename Radio >\n    void ll_data_pdu_buffer< TransmitSize, ReceiveSize, Radio >::commit_transmit_buffer( read_buffer pdu )\n    {\n        if ( stopped_ )\n            return;\n\n        static constexpr std::uint8_t header_rfu_mask = 0xe0;\n        static_cast< void >( header_rfu_mask );\n\n        // make sure, no NFU bits are set\n        std::uint16_t header = layout::header( pdu );\n        assert( ( header & header_rfu_mask ) == 0 );\n\n        typename Radio::lock_guard lock;\n\n        // add sequence number\n        if ( sequence_number_ )\n        {\n            header |= sn_flag;\n            layout::header( pdu, header );\n        }\n\n        sequence_number_ = !sequence_number_;\n\n        transmit_buffer_.push_front( transmit_buffer(), pdu );\n    }\n\n    template < std::size_t TransmitSize, std::size_t ReceiveSize, typename Radio >\n    bool ll_data_pdu_buffer< TransmitSize, ReceiveSize, Radio >::pending_outgoing_data_available() const\n    {\n        return transmit_buffer_.next_end().size != 0;\n    }\n\n    template < std::size_t TransmitSize, std::size_t ReceiveSize, typename Radio >\n    write_buffer ll_data_pdu_buffer< TransmitSize, ReceiveSize, Radio >::set_next_expected_sequence_number( read_buffer buf ) const\n    {\n        // insert the next expected sequence for every attempt to send the PDU, because it could be that\n        // the peripheral is able to receive data, while the central is not able to.\n        std::size_t header = layout::header( buf );\n\n        header = next_expected_sequence_number_\n            ? ( header | nesn_flag )\n            : ( header & ~nesn_flag );\n\n        layout::header( buf, header );\n\n        return write_buffer( buf );\n    }\n\n    template < std::size_t TransmitSize, std::size_t ReceiveSize, typename Radio >\n    write_buffer ll_data_pdu_buffer< TransmitSize, ReceiveSize, Radio >::next_transmit()\n    {\n        const read_buffer next = transmit_buffer_.next_end();\n\n        if ( next_empty_ )\n        {\n            // if an empty buffer have to be resend, flag that there is more data\n            if ( next.size )\n            {\n                const std::uint16_t header = layout::header( next ) | more_data_flag;\n                layout::header( next, header );\n            }\n\n            return set_next_expected_sequence_number( read_buffer{ &empty_[ 0 ], sizeof( empty_ ) } );\n        }\n        else if ( next.size == 0 )\n        {\n            // we created an PDU, so it has to have a new sequnce number\n            const std::uint16_t header = sequence_number_\n                ? sn_flag + ll_empty_id\n                :           ll_empty_id;\n\n            layout::header( empty_, header );\n            next_empty_ = true;\n\n            // keep sequence number of empty in mind and increment sequence_number_\n            empty_sequence_number_ = sequence_number_;\n            sequence_number_ = !sequence_number_;\n\n            return set_next_expected_sequence_number( read_buffer{ &empty_[ 0 ], sizeof( empty_ ) } );\n        }\n\n        if ( transmit_buffer_.more_than_one() )\n            layout::header( next, layout::header( next ) | more_data_flag );\n\n        return set_next_expected_sequence_number( next );\n    }\n\n    template < std::size_t TransmitSize, std::size_t ReceiveSize, typename Radio >\n    void ll_data_pdu_buffer< TransmitSize, ReceiveSize, Radio >::acknowledge( bool nesn )\n    {\n        if ( next_empty_ )\n        {\n            if ( empty_sequence_number_ != nesn )\n                next_empty_ = false;\n        }\n        else\n        {\n            const read_buffer next = transmit_buffer_.next_end();\n\n            // the transmit buffer could be empty if we receive without sending prior. That happens during testing\n            if ( next.empty() )\n                return;\n\n            const std::uint16_t header = layout::header( next );\n            if ( static_cast< bool >( header & sn_flag ) != nesn )\n            {\n                transmit_buffer_.pop_end( transmit_buffer() );\n                static_cast< Radio* >( this )->increment_transmit_packet_counter();\n            }\n        }\n    }\n\n    template < std::size_t TransmitSize, std::size_t ReceiveSize, typename Radio >\n    read_buffer ll_data_pdu_buffer< TransmitSize, ReceiveSize, Radio >::allocate_transmit_buffer()\n    {\n        return allocate_transmit_buffer( max_tx_size_ + layout_overhead );\n    }\n\n    template < std::size_t TransmitSize, std::size_t ReceiveSize, typename Radio >\n    write_buffer ll_data_pdu_buffer< TransmitSize, ReceiveSize, Radio >::next_received() const\n    {\n        typename Radio::lock_guard lock;\n\n        return write_buffer( receive_buffer_.next_end() );\n    }\n\n    template < std::size_t TransmitSize, std::size_t ReceiveSize, typename Radio >\n    void ll_data_pdu_buffer< TransmitSize, ReceiveSize, Radio >::free_received()\n    {\n        typename Radio::lock_guard lock;\n\n        receive_buffer_.pop_end( receive_buffer() );\n    }\n\n    template < std::size_t TransmitSize, std::size_t ReceiveSize, typename Radio >\n    read_buffer ll_data_pdu_buffer< TransmitSize, ReceiveSize, Radio >::allocate_receive_buffer() const\n    {\n        return receive_buffer_.alloc_front( const_cast< std::uint8_t* >( receive_buffer() ), layout::data_channel_pdu_memory_size( max_rx_size_ - ll_header_size ) );\n    }\n\n    template < std::size_t TransmitSize, std::size_t ReceiveSize, typename Radio >\n    write_buffer ll_data_pdu_buffer< TransmitSize, ReceiveSize, Radio >::received( read_buffer pdu )\n    {\n        const std::uint16_t header = layout::header( pdu );\n\n        acknowledge( header & nesn_flag );\n\n        // resent PDU?\n        if ( static_cast< bool >( header & sn_flag ) == next_expected_sequence_number_ )\n        {\n            next_expected_sequence_number_ = !next_expected_sequence_number_;\n\n            if ( ( header & 0xff00 ) != 0 )\n            {\n                // invalid LLID\n                if ( ( header & 0x3 ) != 0 )\n                    receive_buffer_.push_front( receive_buffer(), pdu );\n\n                static_cast< Radio* >( this )->increment_receive_packet_counter();\n            }\n        }\n\n        return next_transmit();\n    }\n\n    template < std::size_t TransmitSize, std::size_t ReceiveSize, typename Radio >\n    write_buffer ll_data_pdu_buffer< TransmitSize, ReceiveSize, Radio >::acknowledge( read_buffer pdu )\n    {\n        const std::uint16_t header = layout::header( pdu );\n\n        // invalid LLID\n        if ( ( header & 0x3 ) != 0 )\n        {\n            acknowledge( header & nesn_flag );\n\n            // resent PDU?\n            if ( static_cast< bool >( header & sn_flag ) == next_expected_sequence_number_ )\n            {\n                next_expected_sequence_number_ = !next_expected_sequence_number_;\n            }\n        }\n\n        return next_transmit();\n    }\n\n}\n}\n\n#endif\n"
  },
  {
    "path": "bluetoe/link_layer/include/bluetoe/ll_l2cap_sdu_buffer.hpp",
    "content": "#ifndef BLUETOE_LINK_LAYER_L_L2CAP_SDU_BUFFER_HPP\n#define BLUETOE_LINK_LAYER_L_L2CAP_SDU_BUFFER_HPP\n\n#include <bluetoe/buffer.hpp>\n#include <bluetoe/codes.hpp>\n#include <bluetoe/bits.hpp>\n\nnamespace bluetoe {\nnamespace link_layer {\n\n    /**\n     * @brief buffer responsible for fragment or defragment L2CAP SDUs\n     *\n     * If the L2CAP MTU size is 23, this class shall no generate any overhead as SDUs are directly\n     * mapped to LL PDUs.\n     *\n     * @tparam ReceiveCallbacks type that has to provide a callback for raw received PDUs\n     */\n    template < class BufferedRadio, class ReceiveCallbacks, std::size_t MTUSize >\n    class ll_l2cap_sdu_buffer : public BufferedRadio\n    {\n    public:\n        ll_l2cap_sdu_buffer();\n\n        /**\n         * @brief allocate a L2CAP buffer that is ready to be filled by the L2CAP layer\n         *\n         * If the request can not be fullfilled, the returned buffer will have a zero size.\n         * After the buffer was filled by the L2CAP layer, commit_l2cap_transmit_buffer() must\n         * be called to transmit the buffer.\n         *\n         * @param payload_size the payload size of the requested L2CAP buffer, must be >= 0 and <= MTUSize\n         */\n        read_buffer allocate_l2cap_transmit_buffer( std::size_t payload_size );\n\n        /**\n         * @brief allocates a LL buffer that is suitable for the given payload size\n         *\n         * If the request can not be fullfilled, the function will return an empty buffer.\n         * After the buffer was filled by the link layer, commit_ll_transmit_buffer() must\n         * be called to transmit the buffer.\n         */\n        read_buffer allocate_ll_transmit_buffer( std::size_t payload_size );\n\n        /**\n         * @brief schedules the given buffer to be send by the radio\n         *\n         * buffer must have been obtained by a call to allocate_l2cap_transmit_buffer()\n         */\n        void commit_l2cap_transmit_buffer( read_buffer buffer );\n\n        /**\n         * @brief schedules the given buffer to be send by the radio\n         *\n         * buffer must have been obtained by a call to allocate_ll_transmit_buffer()\n         */\n        void commit_ll_transmit_buffer( read_buffer buffer );\n\n        /**\n         * @brief returns the oldest link layer PDU or L2CAP SDU out of the receive buffer.\n         *\n         * If there is no oldest received PDU/SDU, an empty PDU will be returned (size == 0 ).\n         * The returned PDU is not removed from the buffer. To remove the buffer after it is\n         * not used any more, free_ll_l2cap_received() must be called.\n         *\n         * If there are pending outgoing PDUs there will be an attempt to write them to the\n         * link layer.\n         *\n         * @pre buffer is in running mode\n         *\n         * @sa free_ll_l2cap_received()\n         */\n        write_buffer next_ll_l2cap_received();\n\n        /**\n         * @brief removes the oldest PDU from the receive buffer.\n         * @pre next_ll_received() was called without free_ll_received() beeing called.\n         * @pre buffer is in running mode\n         */\n        void free_ll_l2cap_received();\n\n        /**\n         * @brief radio layout assumed by the buffer\n         */\n        using layout = typename BufferedRadio::layout;\n\n    private:\n        static constexpr std::uint16_t  pdu_type_mask           = 0x0003;\n        static constexpr std::uint16_t  pdu_type_link_layer     = 0x0003;\n        static constexpr std::uint16_t  pdu_type_start          = 0x0002;\n        static constexpr std::uint16_t  pdu_type_continuation   = 0x0001;\n\n        static constexpr std::size_t    header_size             = BufferedRadio::header_size;\n        static constexpr std::size_t    layout_overhead         = BufferedRadio::layout_overhead;\n        static constexpr std::size_t    l2cap_header_size       = 4u;\n        static constexpr std::size_t    overall_overhead        = header_size + layout_overhead + l2cap_header_size;\n        static constexpr std::size_t    ll_overhead             = header_size + layout_overhead;\n\n        void add_to_receive_buffer( const std::uint8_t*, const std::uint8_t* );\n        void try_send_pdus();\n\n        std::uint8_t    receive_buffer_[ MTUSize + overall_overhead ];\n        std::uint16_t   receive_size_;\n        std::size_t     receive_buffer_used_;\n\n        // when transmitting L2CAP PDUs, we need room for at least the first LL header. Otherwise,\n        // it would not be possible to transparently replace commit_l2cap_transmit_buffer()\n        // transparently with commit_transmit_buffer() for the case that fragmentation is not\n        // used.\n        std::uint8_t    transmit_buffer_[ MTUSize + overall_overhead ];\n        std::uint16_t   transmit_size_;\n        std::size_t     transmit_buffer_used_;\n    };\n\n    /**\n     * @brief specialisation for the minimum MTU size, which would not require any addition\n     *        fragmentation / defragmentation\n     */\n    template < class BufferedRadio, class ReceiveCallbacks >\n    class ll_l2cap_sdu_buffer< BufferedRadio, ReceiveCallbacks, bluetoe::details::default_att_mtu_size > : public BufferedRadio\n    {\n    public:\n        read_buffer allocate_l2cap_transmit_buffer( std::size_t size );\n        read_buffer allocate_ll_transmit_buffer( std::size_t size );\n        void commit_l2cap_transmit_buffer( read_buffer buffer );\n        void commit_ll_transmit_buffer( read_buffer buffer );\n        write_buffer next_ll_l2cap_received() const;\n        void free_ll_l2cap_received();\n    private:\n        static constexpr std::size_t    header_size             = BufferedRadio::header_size;\n        static constexpr std::size_t    layout_overhead         = BufferedRadio::layout_overhead;\n        static constexpr std::size_t    l2cap_header_size       = 4u;\n        static constexpr std::size_t    overall_overhead        = header_size + layout_overhead + l2cap_header_size;\n        static constexpr std::size_t    ll_overhead             = header_size + layout_overhead;\n    };\n\n    // implementation\n    template < class BufferedRadio, class ReceiveCallbacks, std::size_t MTUSize >\n    ll_l2cap_sdu_buffer< BufferedRadio, ReceiveCallbacks, MTUSize >::ll_l2cap_sdu_buffer()\n        : receive_size_( 0 )\n        , receive_buffer_used_( 0 )\n        , transmit_size_( 0 )\n        , transmit_buffer_used_( 0 )\n    {\n    }\n\n    template < class BufferedRadio, class ReceiveCallbacks, std::size_t MTUSize >\n    read_buffer ll_l2cap_sdu_buffer< BufferedRadio, ReceiveCallbacks, MTUSize >::allocate_l2cap_transmit_buffer( std::size_t payload_size )\n    {\n        assert( payload_size <= MTUSize );\n\n        if ( transmit_buffer_used_ != 0 ||  transmit_size_ != 0 )\n            return { nullptr, 0 };\n\n        return { transmit_buffer_, payload_size + overall_overhead };\n    }\n\n    template < class BufferedRadio, class ReceiveCallbacks, std::size_t MTUSize >\n    read_buffer ll_l2cap_sdu_buffer< BufferedRadio, ReceiveCallbacks, MTUSize >::allocate_ll_transmit_buffer( std::size_t payload_size )\n    {\n        try_send_pdus();\n\n        return this->allocate_transmit_buffer( payload_size + ll_overhead );\n    }\n\n    template < class BufferedRadio, class ReceiveCallbacks, std::size_t MTUSize >\n    void ll_l2cap_sdu_buffer< BufferedRadio, ReceiveCallbacks, MTUSize >::commit_l2cap_transmit_buffer( read_buffer buffer )\n    {\n        const auto          body    = layout::body( buffer );\n        const std::size_t   size    = bluetoe::details::read_16bit( body.first ) + overall_overhead;\n\n        transmit_buffer_used_       = 0;\n        transmit_size_              = size;\n\n        try_send_pdus();\n    }\n\n    template < class BufferedRadio, class ReceiveCallbacks, std::size_t MTUSize >\n    void ll_l2cap_sdu_buffer< BufferedRadio, ReceiveCallbacks, MTUSize >::commit_ll_transmit_buffer( read_buffer buffer )\n    {\n        this->commit_transmit_buffer( buffer );\n    }\n\n    template < class BufferedRadio, class ReceiveCallbacks, std::size_t MTUSize >\n    write_buffer ll_l2cap_sdu_buffer< BufferedRadio, ReceiveCallbacks, MTUSize >::next_ll_l2cap_received()\n    {\n        try_send_pdus();\n\n        // is there already a defragmented L2CAP SDU?\n        if ( receive_buffer_used_ != 0 && receive_size_ == 0 )\n            return { receive_buffer_, receive_buffer_used_ };\n\n        for ( auto pdu = this->next_received(); pdu.size; pdu = this->next_received() )\n        {\n            const std::uint16_t header = layout::header( pdu );\n            const std::uint16_t type   = header & pdu_type_mask;\n\n            // link layer control PDUs are not fragmented by default\n            if ( type == pdu_type_link_layer )\n                return pdu;\n\n            static_cast< ReceiveCallbacks* >( this )->pdu_receive_data_callback( pdu );\n\n            // l2cap message\n            const auto          body        = layout::body( pdu );\n            const std::size_t   body_size   = body.second - body.first;\n\n            if ( type == pdu_type_start )\n            {\n                if ( body_size >= l2cap_header_size )\n                {\n                    const std::uint16_t l2cap_size  = bluetoe::details::read_16bit( body.first );\n\n                    // short l2cap PDU that is not fragmented\n                    if ( l2cap_size + l2cap_header_size == body_size )\n                        return pdu;\n\n                    if ( l2cap_size <= MTUSize )\n                    {\n                        receive_size_ = l2cap_size + overall_overhead;\n                        add_to_receive_buffer( pdu.buffer, pdu.buffer + pdu.size );\n                    }\n                }\n            }\n            else\n            {\n                add_to_receive_buffer( body.first, body.second );\n            }\n\n            // consume LL PDU\n            this->free_received();\n\n            // is there now a defragmented L2CAP SDU?\n            if ( receive_buffer_used_ != 0 && receive_size_ == 0 )\n                return { receive_buffer_, receive_buffer_used_ };\n        }\n\n        return { nullptr, 0 };\n    }\n\n    template < class BufferedRadio, class ReceiveCallbacks, std::size_t MTUSize >\n    void ll_l2cap_sdu_buffer< BufferedRadio, ReceiveCallbacks, MTUSize >::add_to_receive_buffer( const std::uint8_t* begin, const std::uint8_t* end )\n    {\n        const std::size_t copy_size = std::min< std::size_t >( receive_size_, end - begin );\n\n        std::copy( begin, end, &receive_buffer_[ receive_buffer_used_ ] );\n        receive_buffer_used_ += copy_size;\n        receive_size_ -= copy_size;\n    }\n\n    template < class BufferedRadio, class ReceiveCallbacks, std::size_t MTUSize >\n    void ll_l2cap_sdu_buffer< BufferedRadio, ReceiveCallbacks, MTUSize >::try_send_pdus()\n    {\n        while ( transmit_size_ )\n        {\n            const bool first_fragment   = transmit_buffer_used_ == 0;\n\n            // for the first PDU, the header overhead is already taken into account. For all additonal fragments,\n            // an additional header has to be allocated.\n            const std::size_t overhead  = first_fragment ? 0 : ll_overhead;\n            const auto buffer           = this->allocate_transmit_buffer( std::min( transmit_size_ + overhead, this->max_tx_size() ) );\n\n            if ( buffer.size == 0 )\n                return;\n\n            if ( first_fragment )\n            {\n                // The first fragment contains the original LL header\n                const auto copy_size = std::min< std::size_t >( buffer.size, transmit_size_ );\n\n                std::copy( &transmit_buffer_[ 0 ], &transmit_buffer_[ copy_size ], buffer.buffer );\n                layout::header( buffer, pdu_type_start | ( ( copy_size - ll_overhead ) << 8 ) );\n\n                transmit_size_        -= copy_size;\n                transmit_buffer_used_ += copy_size;\n            }\n            else\n            {\n                // for every additional fragment, an additional header has to be generated\n                const auto body        = layout::body( buffer );\n                const auto copy_size   = std::min< std::size_t >( std::distance( body.first, body.second ), transmit_size_ );\n\n                std::copy( &transmit_buffer_[ transmit_buffer_used_ ], &transmit_buffer_[ transmit_buffer_used_+ copy_size ], body.first );\n                layout::header( buffer, pdu_type_continuation | ( copy_size << 8 ) );\n\n                transmit_size_        -= copy_size;\n                transmit_buffer_used_ += copy_size;\n            }\n\n            this->commit_transmit_buffer( buffer );\n        }\n\n        transmit_buffer_used_ = 0;\n    }\n\n    template < class BufferedRadio, class ReceiveCallbacks, std::size_t MTUSize >\n    void ll_l2cap_sdu_buffer< BufferedRadio, ReceiveCallbacks, MTUSize >::free_ll_l2cap_received()\n    {\n        if (receive_buffer_used_)\n        {\n            receive_buffer_used_ = 0;\n            receive_size_ = 0;\n        }\n        else\n        {\n            this->free_received();\n        }\n    }\n\n\n    // implementation\n    template < class BufferedRadio, class ReceiveCallbacks >\n    read_buffer ll_l2cap_sdu_buffer< BufferedRadio, ReceiveCallbacks, bluetoe::details::default_att_mtu_size >::allocate_l2cap_transmit_buffer( std::size_t size )\n    {\n        return this->allocate_transmit_buffer( size + overall_overhead );\n    }\n\n    template < class BufferedRadio, class ReceiveCallbacks >\n    read_buffer ll_l2cap_sdu_buffer< BufferedRadio, ReceiveCallbacks, bluetoe::details::default_att_mtu_size >::allocate_ll_transmit_buffer( std::size_t size )\n    {\n        return this->allocate_transmit_buffer( size + ll_overhead );\n    }\n\n    template < class BufferedRadio, class ReceiveCallbacks >\n    void ll_l2cap_sdu_buffer< BufferedRadio, ReceiveCallbacks, bluetoe::details::default_att_mtu_size >::commit_l2cap_transmit_buffer( read_buffer buffer )\n    {\n        return this->commit_transmit_buffer( buffer );\n    }\n\n    template < class BufferedRadio, class ReceiveCallbacks >\n    void ll_l2cap_sdu_buffer< BufferedRadio, ReceiveCallbacks, bluetoe::details::default_att_mtu_size >::commit_ll_transmit_buffer( read_buffer buffer )\n    {\n        return this->commit_transmit_buffer( buffer );\n    }\n\n    template < class BufferedRadio, class ReceiveCallbacks >\n    write_buffer ll_l2cap_sdu_buffer< BufferedRadio, ReceiveCallbacks, bluetoe::details::default_att_mtu_size >::next_ll_l2cap_received() const\n    {\n        return this->next_received();\n    }\n\n    template < class BufferedRadio, class ReceiveCallbacks >\n    void ll_l2cap_sdu_buffer< BufferedRadio, ReceiveCallbacks, bluetoe::details::default_att_mtu_size >::free_ll_l2cap_received()\n    {\n        return this->free_received();\n    }\n}\n}\n\n#endif\n"
  },
  {
    "path": "bluetoe/link_layer/include/bluetoe/ll_meta_types.hpp",
    "content": "#ifndef BLUETOE_LINK_LAYER_META_TYPES_HPP\n#define BLUETOE_LINK_LAYER_META_TYPES_HPP\n\nnamespace bluetoe {\n    namespace link_layer {\n        namespace details {\n\n            /**\n             * meta type to tag a valid option to the link layer\n             */\n            struct valid_link_layer_option_meta_type {};\n        }\n    }\n}\n#endif\n"
  },
  {
    "path": "bluetoe/link_layer/include/bluetoe/ll_options.hpp",
    "content": "#ifndef BLUETOE_LINK_LAYER_OPTIONS_HPP\n#define BLUETOE_LINK_LAYER_OPTIONS_HPP\n\n#include <bluetoe/address.hpp>\n#include <bluetoe/connection_details.hpp>\n#include <bluetoe/ll_meta_types.hpp>\n\n\nnamespace bluetoe\n{\nnamespace link_layer\n{\n    namespace details {\n        struct device_address_meta_type {};\n        struct buffer_sizes_meta_type {};\n        struct desired_connection_parameters_meta_type {};\n        struct custom_l2cap_layer_meta_type {};\n        struct ll_pdu_receive_data_callback_meta_type {};\n    }\n\n    /**\n     * @brief defines that the device will use a static random address.\n     *\n     * A static random address is an address that is random, but stays the same every time the device starts.\n     * A static random address is the default.\n     */\n    struct random_static_address\n    {\n        /**\n         * @brief returns true, because this is a random address\n         */\n        static constexpr bool is_random()\n        {\n            return true;\n        }\n\n        /**\n         * @brief takes a scheduled radio and generates a random static address\n         */\n        template < class Radio >\n        static random_device_address address( const Radio& r )\n        {\n            return address::generate_static_random_address( r.static_random_address_seed() );\n        }\n\n        /** @cond HIDDEN_SYMBOLS */\n        struct meta_type :\n            details::device_address_meta_type,\n            details::valid_link_layer_option_meta_type {};\n        /** @endcond */\n    };\n\n    /**\n     * @brief defines a defined static random address\n     *\n     * The address will be A:B:C:D:E:F\n     */\n    template < std::uint8_t A, std::uint8_t B, std::uint8_t C, std::uint8_t D, std::uint8_t E, std::uint8_t F >\n    struct static_address\n    {\n        /**\n         * @brief returns true, because this is a random address\n         */\n        static constexpr bool is_random()\n        {\n            return true;\n        }\n\n        /**\n         * @brief returns the static, configured address A:B:C:D:E:F\n         */\n        template < class Radio >\n        static random_device_address address( const Radio& )\n        {\n            static constexpr std::uint8_t addr[] = { F, E, D, C, B, A };\n            return ::bluetoe::link_layer::random_device_address( addr );\n        }\n\n        /** @cond HIDDEN_SYMBOLS */\n        struct meta_type :\n            details::device_address_meta_type,\n            details::valid_link_layer_option_meta_type {};\n        /** @endcond */\n    };\n\n    namespace details {\n        struct sleep_clock_accuracy_meta_type {};\n\n        template < unsigned long long SleepClockAccuracyPPM >\n        struct check_sleep_clock_accuracy_ppm {\n            static_assert( SleepClockAccuracyPPM <= 500, \"The highest, possible sleep clock accuracy is 500ppm.\" );\n\n            typedef void type;\n        };\n\n    }\n\n    /**\n     * @brief defines the sleep clock accuracy of the device hardware.\n     *\n     * The stack uses the accuracy information to keep the time window where the peripheral listens for radio messages\n     * from the central, as small as possible. It's important to determine the real sleep clock accuracy.\n     * Giving to large accuracy will leed to not optimal power consumption.\n     * To small accuracy will leed to instable connections.\n     */\n    template < unsigned long long SleepClockAccuracyPPM, typename = typename details::check_sleep_clock_accuracy_ppm< SleepClockAccuracyPPM >::type >\n    struct sleep_clock_accuracy_ppm\n    {\n        /**\n         * @brief configured sleep clock accuracy\n         */\n        static constexpr unsigned accuracy_ppm = static_cast< unsigned >( SleepClockAccuracyPPM );\n\n        /** @cond HIDDEN_SYMBOLS */\n        struct meta_type :\n            details::sleep_clock_accuracy_meta_type,\n            details::valid_link_layer_option_meta_type {};\n        /** @endcond */\n    };\n\n    /**\n     * @brief defines link layer transmit and receive buffer sizes\n     */\n    template < std::size_t TransmitSize = 61, std::size_t ReceiveSize = 61 >\n    struct buffer_sizes\n    {\n        /** @cond HIDDEN_SYMBOLS */\n        struct meta_type :\n            details::buffer_sizes_meta_type,\n            details::valid_link_layer_option_meta_type {};\n        /** @endcond */\n\n        /**\n         * configured link layer transmit buffer size in bytes.\n         */\n        static constexpr std::size_t transmit_buffer_size = TransmitSize;\n\n        /**\n         * configured link layer receive buffer size in bytes.\n         */\n        static constexpr std::size_t receive_buffer_size  = ReceiveSize;\n    };\n\n    namespace details\n    {\n        struct requested_connection_parameters\n        {\n            std::uint16_t min_interval;\n            std::uint16_t max_interval;\n            std::uint16_t latency;\n            std::uint16_t timeout;\n        };\n\n        struct desired_connection_parameters_base\n        {\n            static constexpr std::size_t    size                        = 24;\n            static constexpr std::uint8_t   ll_control_pdu_code         = 3;\n            static constexpr std::uint8_t   LL_CONNECTION_PARAM_REQ     = 0x0F;\n            static constexpr std::uint8_t   LL_CONNECTION_PARAM_RSP     = 0x10;\n            static constexpr std::uint8_t   LL_REJECT_EXT_IND           = 0x11;\n            static constexpr std::uint8_t   invalid_ll_paramerters      = 0x1E;\n            static constexpr std::uint8_t   unacceptable_connection_parameters = 0x3B;\n\n            template < class Layout >\n            static bool parse_and_check_params( const write_buffer& request, read_buffer response, requested_connection_parameters& params )\n            {\n                static constexpr std::uint16_t interval_minimum = 5u;\n                static constexpr std::uint16_t interval_maximum = 3200u;\n                static constexpr std::uint16_t latency_maximum  = 499u;\n\n                const std::uint8_t* const body       = Layout::body( request ).first;\n\n                using bluetoe::details::read_16bit;\n\n                params.min_interval = read_16bit( body + 1 );\n                params.max_interval = read_16bit( body + 3 );\n                params.latency      = read_16bit( body + 5 );\n                params.timeout      = read_16bit( body + 7 );\n\n                if ( params.max_interval < params.min_interval\n                  || params.min_interval < interval_minimum\n                  || params.max_interval > interval_maximum\n                  || params.latency > latency_maximum )\n                {\n                    fill< Layout >( response, {\n                        ll_control_pdu_code, 3,\n                        LL_REJECT_EXT_IND,\n                        LL_CONNECTION_PARAM_REQ,\n                        invalid_ll_paramerters\n                    } );\n\n                    return false;\n                }\n\n                return true;\n            }\n        };\n    }\n\n    /**\n     * @brief static, desired connection parameters\n     *\n     * Connection parameters that the peripheral desires to have established.\n     * This feature is experimental and but now, it will just fill the given\n     * parameters in the LL_CONNECTION_PARAM_RSP response.\n     *\n     * Finally, Bluetoe should implement some mean / algorithm / heuristic to\n     * establish the desired connection parameters. (for example, by requesting\n     * them from the Central).\n     *\n     * @sa asynchronous_connection_parameter_request\n     */\n    template <\n        std::uint16_t Interval_min,\n        std::uint16_t Interval_max,\n        std::uint16_t Latency_min,\n        std::uint16_t Latency_max,\n        std::uint16_t Timeout_min,\n        std::uint16_t Timeout_max >\n    struct desired_connection_parameters : private details::desired_connection_parameters_base\n    {\n        /** @cond HIDDEN_SYMBOLS */\n        struct meta_type :\n            details::desired_connection_parameters_meta_type,\n            details::valid_link_layer_option_meta_type {};\n\n        template < class Layout >\n        bool handle_connection_parameters_request(\n            const write_buffer& request, read_buffer response, const connection_details& )\n        {\n            const std::uint8_t* const body       = Layout::body( request ).first;\n                  std::uint8_t* const write_body = Layout::body( response ).first;\n\n            details::requested_connection_parameters params;\n            if ( parse_and_check_params< Layout >( request, response, params ) )\n            {\n                params.min_interval = std::max( params.min_interval, Interval_min );\n                params.max_interval = std::min( params.max_interval, Interval_max );\n\n                if ( params.min_interval > params.max_interval )\n                {\n                    params.min_interval = Interval_min;\n                    params.max_interval = Interval_max;\n                }\n\n                if ( params.latency < Latency_min || params.latency > Latency_max )\n                {\n                    params.latency = ( Latency_min + Latency_max ) / 2;\n                }\n\n                if ( params.timeout < Timeout_min || params.timeout > Timeout_max )\n                {\n                    params.timeout = ( Timeout_min + Timeout_max ) / 2;\n                }\n\n                fill< Layout >( response, {\n                    ll_control_pdu_code, size,\n                    LL_CONNECTION_PARAM_RSP,\n                    static_cast< std::uint8_t >( params.min_interval ),\n                    static_cast< std::uint8_t >( params.min_interval >> 8 ),\n                    static_cast< std::uint8_t >( params.max_interval ),\n                    static_cast< std::uint8_t >( params.max_interval >> 8 ),\n                    static_cast< std::uint8_t >( params.latency ),\n                    static_cast< std::uint8_t >( params.latency >> 8 ),\n                    static_cast< std::uint8_t >( params.timeout ),\n                    static_cast< std::uint8_t >( params.timeout >> 8 )\n                } );\n\n                std::copy( &body[ 9 ], &body[ size ], &write_body[ 9 ] );\n            }\n\n            return true;\n        }\n\n        template < class Layout >\n        void connection_parameters_response_fill( read_buffer )\n        {}\n\n        bool connection_parameters_response_pending() const\n        {\n            return false;\n        }\n\n        void reset_connection_parameter_request()\n        {}\n        /** @endcond */\n    };\n\n    /**\n     * @brief configures the link_layer to implement the connection parameter update request / response\n     *        by upcalling a callback and then awaiting an response from the application.\n     *\n     * @sa desired_connection_parameters\n     */\n    template < class Callback, Callback& Obj >\n    struct asynchronous_connection_parameter_request : private details::desired_connection_parameters_base\n    {\n    public:\n        void connection_parameters_request_reply(\n            std::uint16_t interval_min,\n            std::uint16_t interval_max,\n            std::uint16_t latency,\n            std::uint16_t timeout )\n        {\n            pending_ = true;\n            negative_ = false;\n            interval_min_ = interval_min;\n            interval_max_ = interval_max;\n            latency_      = latency;\n            timeout_      = timeout;\n        }\n\n        void connection_parameters_request_negative_reply( std::uint8_t reason )\n        {\n            pending_ = true;\n            negative_ = true;\n            reason_ = reason;\n        }\n\n        /** @cond HIDDEN_SYMBOLS */\n        struct meta_type :\n            details::desired_connection_parameters_meta_type,\n            details::valid_link_layer_option_meta_type {};\n\n    protected:\n        template < class Layout >\n        bool handle_connection_parameters_request(\n            const write_buffer& request, read_buffer response, const connection_details& details )\n        {\n            details::requested_connection_parameters params;\n            if ( !parse_and_check_params< Layout >( request, response, params ) )\n                return true;\n\n            if ( params.min_interval == params.max_interval\n              && params.min_interval == details.interval()\n              && params.latency == details.latency()\n              && params.timeout == details.timeout() )\n            {\n                const std::uint8_t* const body       = Layout::body( request ).first;\n                      std::uint8_t* const write_body = Layout::body( response ).first;\n\n                fill< Layout >( response, { ll_control_pdu_code, size, LL_CONNECTION_PARAM_RSP } );\n\n                std::copy( &body[ 1 ], &body[ 1 + size - 1 ], &write_body[ 1 ] );\n\n                return true;\n            }\n\n            Obj.ll_remote_connection_parameter_request(\n                params.min_interval, params.max_interval,\n                params.latency, params.timeout );\n\n            return false;\n        }\n\n        template < class Layout >\n        void connection_parameters_response_fill( read_buffer response )\n        {\n            if ( negative_ )\n            {\n                fill< Layout >( response, {\n                    ll_control_pdu_code, 3,\n                    LL_REJECT_EXT_IND,\n                    LL_CONNECTION_PARAM_REQ,\n                    reason_\n                } );\n            }\n            else\n            {\n                fill< Layout >( response, {\n                    ll_control_pdu_code, size,\n                    LL_CONNECTION_PARAM_RSP,\n                    static_cast< std::uint8_t >( interval_min_ ),\n                    static_cast< std::uint8_t >( interval_min_ >> 8 ),\n                    static_cast< std::uint8_t >( interval_max_ ),\n                    static_cast< std::uint8_t >( interval_max_ >> 8 ),\n                    static_cast< std::uint8_t >( latency_ ),\n                    static_cast< std::uint8_t >( latency_ >> 8 ),\n                    static_cast< std::uint8_t >( timeout_ ),\n                    static_cast< std::uint8_t >( timeout_ >> 8 ),\n                    0,\n                    0xff, 0xff,\n                    0xff, 0xff,\n                    0xff, 0xff,\n                    0xff, 0xff,\n                    0xff, 0xff,\n                    0xff, 0xff,\n                    0xff, 0xff,\n                } );\n            }\n\n\n            pending_ = false;\n        }\n\n        bool connection_parameters_response_pending() const\n        {\n            return pending_;\n        }\n\n        void reset_connection_parameter_request()\n        {\n            pending_ = false;\n        }\n\n    private:\n        bool pending_;\n        bool negative_;\n        std::uint16_t interval_min_;\n        std::uint16_t interval_max_;\n        std::uint16_t latency_;\n        std::uint16_t timeout_;\n        std::uint8_t  reason_;\n        /** @endcond */\n    };\n\n    /** @cond HIDDEN_SYMBOLS */\n    struct no_desired_connection_parameters : private details::desired_connection_parameters_base\n    {\n        struct meta_type :\n            details::desired_connection_parameters_meta_type,\n            details::valid_link_layer_option_meta_type {};\n\n        template < class Layout >\n        bool handle_connection_parameters_request(\n            const write_buffer& request, read_buffer response, const connection_details& )\n        {\n            details::requested_connection_parameters params;\n            if ( parse_and_check_params< Layout >( request, response, params ) )\n            {\n                const std::uint8_t* const body       = Layout::body( request ).first;\n                      std::uint8_t* const write_body = Layout::body( response ).first;\n\n                fill< Layout >( response, { ll_control_pdu_code, size, LL_CONNECTION_PARAM_RSP } );\n\n                std::copy( &body[ 1 ], &body[ 1 + size - 1 ], &write_body[ 1 ] );\n            }\n\n            return true;\n        }\n\n        template < class Layout >\n        void connection_parameters_response_fill( read_buffer )\n        {}\n\n        bool connection_parameters_response_pending() const\n        {\n            return false;\n        }\n\n        void reset_connection_parameter_request()\n        {}\n\n    };\n    /** @endcond */\n\n    /**\n     * @brief specify the l2cap layer to be used by the link_layer\n     */\n    template < template <class LinkLayer > class L2CapLayer >\n    struct ll_custom_l2cap_layer\n    {\n        /** @cond HIDDEN_SYMBOLS */\n        struct meta_type :\n            details::custom_l2cap_layer_meta_type,\n            details::valid_link_layer_option_meta_type {};\n\n        template < class LinkLayer >\n        using l2cap_layer = L2CapLayer< LinkLayer >;\n        /** @endcond */\n    };\n\n    template < class Obj, Obj& obj >\n    struct l2cap_callback\n    {\n        /** @cond HIDDEN_SYMBOLS */\n        void pdu_receive_data_callback( const write_buffer& ll_pdu_containing_l2cap_package )\n        {\n            obj.l2cap_callback( ll_pdu_containing_l2cap_package );\n        }\n\n        struct meta_type :\n            details::ll_pdu_receive_data_callback_meta_type,\n            details::valid_link_layer_option_meta_type {};\n    };\n\n    struct no_l2cap_callback\n    {\n        /** @cond HIDDEN_SYMBOLS */\n        void pdu_receive_data_callback( const write_buffer& )\n        {\n        }\n\n        struct meta_type :\n            details::ll_pdu_receive_data_callback_meta_type,\n            details::valid_link_layer_option_meta_type {};\n    };\n\n\n}\n}\n\n#endif\n"
  },
  {
    "path": "bluetoe/link_layer/include/bluetoe/peripheral_latency.hpp",
    "content": "#ifndef BLUETOE_LINK_LAYER_PERIPHERAL_LATENCY_HPP\n#define BLUETOE_LINK_LAYER_PERIPHERAL_LATENCY_HPP\n\n#include <bluetoe/ll_meta_types.hpp>\n#include <bluetoe/connection_events.hpp>\n\n/**\n * @file bluetoe/peripheral_latency.hpp\n *\n * This file provides several options, that allow users to configure Bluetoe's\n * support for peripheral latency.\n * Peripheral latency allows a link layer peripheral to ignore some connection events\n * (do not respond to the central) to conserve power.\n *\n * Each option is a compromise between latency and power consumption.\n *\n * @sa bluetoe::link_layer::peripheral_latency_ignored\n * @sa ...\n */\nnamespace bluetoe {\nnamespace link_layer {\n\n    namespace details {\n        struct peripheral_latency_meta_type {};\n    }\n\n    /**\n     * @brief this constant is defined by the core spec\n     */\n    static constexpr auto       maximum_link_layer_peripheral_latency = 499;\n\n    /**\n     * @brief detailed options for the peripheral latency behavior\n     *\n     * Every option defines a set of events / circumstances under which\n     * the link layer should listen at the very next connection event.\n     * Regardless of the selected options, the link layer always listens\n     * for incoming PDU at each peripheral latency anchor points, which\n     * were negotiated as part of the current connection parameters.\n     *\n     * @note in combination, there are some options that make no sense.\n     *       For example, using listen_always with some of the other\n     *       listen_* options is pointless and will result in failure to compile.\n     */\n    enum class peripheral_latency\n    {\n        /**\n         * @brief listen at the very next connection event if bluetoe\n         * has an available PDU for sending.\n         *\n         * This reduces the latency of any available payload. If outgoing\n         * payload becomes available while the next connection event was\n         * planned to utilize peripheral latency, the library tries to\n         * reschedule the next connection event to happen earlier.\n         */\n        listen_if_pending_transmit_data,\n\n        /**\n         * @brief listen if the link layer contains unacknowledged data.\n         *\n         * If a PDU was sent, but no acknowledgement has been received,\n         * the link layer will listen at the next connection event.\n         *\n         * This might be interesting, if the sending queue is very small because\n         * Bluetoe has to keep a copy of a transmitted PDU, as long as that PDU\n         * is not acknowledged.\n         */\n        listen_if_unacknowledged_data,\n\n        /**\n         * @brief listen to the next connection event, if the last received PDU was\n         *        not empty.\n         */\n        listen_if_last_received_not_empty,\n\n        /**\n         * @brief listen to the next connection event, if the last transmitted PDU was\n         *        not empty.\n         */\n        listen_if_last_transmitted_not_empty,\n\n        /**\n         * @brief listen to the next connection event, if the last received PDU had\n         *        the more data (MD) flag set.\n         *\n         * With the MD flag, the central (and the peripheral) can indicate, that there\n         * is more data to be sent. Usually this data is then transmitted during the same\n         * connection event. If there is no support for handling more data in the same\n         * connection event either by the peripheral or by the central, then this option\n         * may help reducing the latency of the pending data.\n         */\n        listen_if_last_received_had_more_data,\n\n        /**\n         * @brief listen at all connection events, despite the negotiated\n         *        peripheral latency value of the current connection.\n         */\n        listen_always,\n\n    };\n\n    namespace details {\n        template < peripheral_latency >\n        struct wrap_latency_option {};\n\n        template < peripheral_latency RequestedFeature, peripheral_latency ... Options >\n        struct feature_enabled\n        {\n            using type = typename bluetoe::details::select_type<\n                bluetoe::details::has_option< wrap_latency_option< RequestedFeature >, wrap_latency_option< Options >... >::value,\n                std::true_type,\n                std::false_type >::type;\n\n            static constexpr bool value = type::value;\n        };\n    }\n\n    /**\n     * @brief defines a peripheral configuration to be used by the link layer\n     *\n     * The configuration is a set of options from peripheral_latency. Example:\n     *\n     * @code{.cpp}\n     * bluetoe::device<\n     *    gatt_server_definition,\n     *    bluetoe::link_layer::peripheral_latency_configuration<\n     *        bluetoe::link_layer::peripheral_latency::listen_if_unacknowledged_data,\n     *        bluetoe::link_layer::peripheral_latency::listen_if_last_received_had_error\n     *    >\n     * > gatt_server;\n     * @endcode\n     *\n     * @sa bluetoe::link_layer::peripheral_latency\n     * @sa bluetoe::link_layer::peripheral_latency_configuration_set\n     */\n    template < peripheral_latency ... Options >\n    struct peripheral_latency_configuration\n    {\n        /** @cond HIDDEN_SYMBOLS */\n        struct meta_type :\n            details::peripheral_latency_meta_type,\n            details::valid_link_layer_option_meta_type {};\n        /** @endcond */\n    };\n\n    /**\n     * @brief allows the peripheral latency configuration to be changed at runtime\n     *        between a given set of configurations.\n     *\n     * Every given Configurations has to be a vaild peripheral_latency_configuration<>.\n     *\n     * For example:\n     *\n     * @code{.cpp}\n     * bluetoe::device<\n     *    gatt_server_definition,\n     *    bluetoe::link_layer::peripheral_latency_configuration_set<\n     *        bluetoe::link_layer::peripheral_latency::peripheral_latency_ignored,\n     *        bluetoe::link_layer::peripheral_latency::peripheral_latency_strict_plus >\n     *    >\n     * > gatt_server;\n     *\n     * void foo()\n     * {\n     *     gatt_server.change_peripheral_latency<\n     *         bluetoe::link_layer::peripheral_latency::peripheral_latency_ignored >();\n     * }\n     * @endcode\n     *\n     * @sa bluetoe::link_layer::peripheral_latency_configuration\n     */\n    template < typename ... Configurations >\n    class peripheral_latency_configuration_set\n    {\n    public:\n        /**\n         * @brief change to a different peripheral latency configuration\n         *\n         * NewConfig will be the new configuration. NewConfig has be an\n         * element of Configurations...\n         */\n        template < typename NewConfig >\n        void change_peripheral_latency();\n\n        /** @cond HIDDEN_SYMBOLS */\n        struct meta_type :\n            details::peripheral_latency_meta_type,\n            details::valid_link_layer_option_meta_type {};\n        /** @endcond */\n    };\n\n    /**\n     * @brief Instructs the link layer to ignore peripheral latency\n     *\n     * The link layer will listen at every connection event and will respond at every\n     * connection event.\n     *\n     * This option will provide lowest latency without any chance to conserve power.\n     *\n     * @sa bluetoe::link_layer::peripheral_latency_configuration\n     */\n    using peripheral_latency_ignored = peripheral_latency_configuration<\n        peripheral_latency::listen_always\n    >;\n\n    /**\n     * @brief Configure the link layer to only listen every configured connection event.\n     *\n     * The link layer will only listen to the central every \"peripheral latency\" + 1 connection\n     * events. If for example, the peripheral latency of the current connection is 4, the link\n     * layer will just listen to every 5th connection event.\n     *\n     * If there is pending, outgoing data, the link layer will start to listen on the next possible\n     * connection event to be able to reply with the pending data. Also, if a received PDU has the\n     * more data (MD) flag beeing set, the link layer will start listening at the next connection event\n     * and transmit the pending data.\n     *\n     * This option provided lowest power consumption while providing better transmitting latency compared\n     * to having a connection interval equal to peripheral latency + 1 * interval.\n     *\n     * @sa bluetoe::link_layer::peripheral_latency_always_listening\n     */\n    using peripheral_latency_strict = peripheral_latency_configuration<\n        peripheral_latency::listen_if_pending_transmit_data,\n        peripheral_latency::listen_if_last_received_had_more_data\n    >;\n\n    /**\n     * @brief Configure the link layer to just listen every configured connection event\n     *        and on the next connection events if the previous connection event contained data\n     *        from the central.\n     *\n     * This option extends the peripheral_latency_strict option by listening\n     * on subsequent events, if there was data received at the previous event.\n     *\n     * This option provided lowest power consumption while providing better transmitting latency compared\n     * to having a connection interval equal to peripheral latency + 1 * interval. Compared to\n     * peripheral_latency_strict, this might increase the receiving bandwidth.\n     *\n     * @sa bluetoe::link_layer::peripheral_latency_always_listening\n     * @sa bluetoe::link_layer::peripheral_latency_strict\n     */\n    using peripheral_latency_strict_plus = peripheral_latency_configuration<\n        peripheral_latency::listen_if_last_received_not_empty,\n        peripheral_latency::listen_if_last_received_had_more_data\n    >;\n\n    /**\n     * @brief Default peripheral latency configuration\n     *\n     * This configuration is used by bluetoe::link_layer::link_layer.\n     *\n     * @sa bluetoe::link_layer::peripheral_latency::listen_if_pending_transmit_data\n     * @sa bluetoe::link_layer::peripheral_latency::listen_if_unacknowledged_data\n     * @sa bluetoe::link_layer::peripheral_latency::listen_if_last_received_not_empty\n     * @sa bluetoe::link_layer::peripheral_latency::listen_if_last_transmitted_not_empty\n     * @sa bluetoe::link_layer::peripheral_latency::listen_if_last_received_had_more_data\n     */\n    using periperal_latency_default_configuration = peripheral_latency_configuration<\n        peripheral_latency::listen_if_pending_transmit_data,\n        peripheral_latency::listen_if_unacknowledged_data,\n        peripheral_latency::listen_if_last_received_not_empty,\n        peripheral_latency::listen_if_last_transmitted_not_empty,\n        peripheral_latency::listen_if_last_received_had_more_data\n    >;\n\n    namespace details {\n\n        /**\n         * @brief this class implements the decisions regarding, when the next connection\n         *        event is planned, based on the events happend at the last connection event\n         *        and the configuration.\n         *\n         * The class implements this by forwarding some of the required pieces of information\n         * to it's base class (strategy pattern).\n         */\n        template < class Base >\n        class connection_state_base\n        {\n        public:\n            /**\n             * @brief index into the channel map for the next, planned connection event\n             */\n            unsigned      current_channel_index() const\n            {\n                return channel_index_;\n            }\n\n            /**\n             * @brief index into the channel map for the next, planned connection event\n             */\n            std::uint16_t connection_event_counter() const\n            {\n                return event_counter_;\n            }\n\n            /**\n             * @brief distance between the last connection event that happend and the next,\n             *        planned connection event.\n             *\n             * The time since last event raised linear with the number of timeouts that occured\n             * on a connection.\n             */\n            delta_time    time_since_last_event() const\n            {\n                return time_since_last_event_;\n            }\n\n            /**\n             * @brief Plan next connection event after timeout\n             */\n            void plan_next_connection_event_after_timeout(\n                delta_time              connection_interval )\n            {\n                channel_index_ = ( channel_index_ + 1 ) % channel_map::max_number_of_data_channels;\n                ++event_counter_;\n                time_since_last_event_ += connection_interval;\n            }\n\n            /**\n             * @brief Plan next connection event\n             */\n            void plan_next_connection_event(\n                std::uint16_t                       connection_peripheral_latency,\n                connection_event_events             last_event_events,\n                delta_time                          connection_interval,\n                std::pair< bool, std::uint16_t >    pending_instance )\n            {\n                if ( ( base().template peripheral_latency_feature< peripheral_latency::listen_if_unacknowledged_data >() and last_event_events.unacknowledged_data )\n                  or ( base().template peripheral_latency_feature< peripheral_latency::listen_if_last_received_not_empty >() and last_event_events.last_received_not_empty )\n                  or ( base().template peripheral_latency_feature< peripheral_latency::listen_if_last_transmitted_not_empty >() and last_event_events.last_transmitted_not_empty )\n                  or ( base().template peripheral_latency_feature< peripheral_latency::listen_if_last_received_had_more_data >() and last_event_events.last_received_had_more_data )\n                  or ( base().template peripheral_latency_feature< peripheral_latency::listen_if_pending_transmit_data >() and last_event_events.pending_outgoing_data )\n                  or ( base().template peripheral_latency_feature< peripheral_latency::listen_always >() )\n                  or ( last_event_events.error_occured  )\n                   )\n                {\n                    connection_peripheral_latency = 0;\n                }\n\n                ++connection_peripheral_latency;\n\n                if ( pending_instance.first )\n                {\n                    const std::uint16_t instance_distance = event_counter_ < pending_instance.second\n                        ? pending_instance.second - event_counter_\n                        : pending_instance.second + ~event_counter_ + 1;\n\n                    if ( instance_distance > 0 )\n                        connection_peripheral_latency = std::min( connection_peripheral_latency, instance_distance );\n                }\n\n                channel_index_  = ( channel_index_ + connection_peripheral_latency ) % channel_map::max_number_of_data_channels;\n                event_counter_ += connection_peripheral_latency;\n                time_since_last_event_ = connection_peripheral_latency * connection_interval;\n\n                base().disarmable_connection_state_last_latency( connection_peripheral_latency );\n            }\n\n            /**\n             * @brief to be called, when pending data to be transmitted is detected\n             *\n             * If listen_if_pending_transmit_data is given as one of the Options,\n             * the passed radio has to implement the disarm_connection_event()\n             * function. If the function returns true, the connection event was disarmed\n             * and a new connection event can be scheduled again.\n             *\n             * @pre there is a connection event pending on the radio\n             * @ret true: there was enough time to disarm the pending connection event\n             */\n            template < class Radio >\n            bool reschedule_on_pending_data( Radio&, delta_time )\n            {\n                return false;\n            }\n\n            /**\n             * @brief connection is just established\n             */\n            void reset_connection_state()\n            {\n                channel_index_         = 0;\n                event_counter_         = 0;\n                time_since_last_event_ = delta_time();\n                base().disarmable_connection_state_last_latency( 1 );\n            }\n\n            void peripheral_latency_move_connection_event( int count, delta_time connection_iterval )\n            {\n                assert( count <= 0 );\n                assert( -count <= maximum_link_layer_peripheral_latency );\n\n                // to have the left side of the modulo beeing always positiv, the largest necessary multiple of\n                // channel_map::max_number_of_data_channels is added. count is bound by the maximum peripheral\n                // latency.\n                static constexpr unsigned offset = ( maximum_link_layer_peripheral_latency / channel_map::max_number_of_data_channels + 1 ) * channel_map::max_number_of_data_channels;\n\n                channel_index_  = ( channel_index_ + count + offset ) % channel_map::max_number_of_data_channels;\n                event_counter_ += count;\n\n                time_since_last_event_ -= -count * connection_iterval;\n            }\n\n        private:\n            unsigned        channel_index_;\n            std::uint16_t   event_counter_;\n            delta_time      time_since_last_event_;\n\n            Base& base()\n            {\n                return *static_cast< Base* >( this );\n            }\n        };\n\n        template < typename DisarmSupport, typename State >\n        class disarmable_connection_state;\n\n        template < typename State >\n        class disarmable_connection_state< std::true_type, State >\n        {\n        public:\n            void disarmable_connection_state_last_latency( int l )\n            {\n                assert( l > 0 );\n                last_latency_ = l;\n            }\n\n        protected:\n            template < class Radio >\n            bool reschedule_on_pending_data_impl( Radio& radio, delta_time connection_iterval )\n            {\n                // Do not try to reschedule an event, that can not be rescheduled or was already\n                // rescheduled.\n                if ( last_latency_ == 1 )\n                    return false;\n\n                const std::pair< bool, bluetoe::link_layer::delta_time > rc = radio.disarm_connection_event();\n\n                if ( rc.first )\n                {\n                    assert( !connection_iterval.zero() );\n\n                    const unsigned times = std::max( 1u, ( rc.second + connection_iterval - delta_time( 1 ) ) / connection_iterval );\n\n                    // only move the connection event further into direction of the current time\n                    const int moved = std::min< int >( times, last_latency_ );\n                    static_cast< State* >( this )->peripheral_latency_move_connection_event( moved - last_latency_, connection_iterval );\n\n                    last_latency_ = 1;\n                }\n\n                return rc.first;\n            }\n\n        private:\n            int last_latency_;\n        };\n\n        template < typename State >\n        class disarmable_connection_state< std::false_type, State >\n        {\n        public:\n            void disarmable_connection_state_last_latency( int ) {}\n\n        protected:\n            template < class Radio >\n            bool reschedule_on_pending_data_impl( Radio&, delta_time )\n            {\n                return false;\n            }\n        };\n\n        /**\n         * @brief book keeping for the current / next connection event\n         */\n        template < typename Options >\n        class peripheral_latency_state;\n\n        template < peripheral_latency ... Options >\n        class peripheral_latency_state< peripheral_latency_configuration< Options... > >\n            : public connection_state_base< peripheral_latency_state< peripheral_latency_configuration< Options... > > >\n            , public disarmable_connection_state<\n                        typename feature_enabled< peripheral_latency::listen_if_pending_transmit_data, Options... >::type,\n                        peripheral_latency_state< peripheral_latency_configuration< Options... > > >\n        {\n        public:\n            static constexpr bool listen_always_given = details::feature_enabled< peripheral_latency::listen_always, Options... >::value;\n            static constexpr bool other_parameters_given = sizeof...( Options ) > 1;\n\n            static_assert( !( listen_always_given and other_parameters_given ),\n                 \"if `listen_always` is given, there is no point in adding addition options\" );\n\n            /**\n             * @brief to be called, when pending data to be transmitted is detected\n             *\n             * If listen_if_pending_transmit_data is given as one of the Options,\n             * the passed radio has to implement the disarm_connection_event()\n             * function. If the function returns true, the connection event was disarmed\n             * and a new connection event can be scheduled again.\n             *\n             * @pre there is a connection event pending on the radio\n             * @ret true: there was enough time to disarm the pending connection event\n             */\n            template < class Radio >\n            bool reschedule_on_pending_data( Radio& radio, delta_time connection_iterval )\n            {\n                return this->reschedule_on_pending_data_impl( radio, connection_iterval );\n            }\n\n            template < peripheral_latency RequestedFeature >\n            constexpr bool peripheral_latency_feature() const\n            {\n                return feature_enabled< RequestedFeature, Options... >::type::value;\n            }\n\n        };\n\n        template < typename ... Configurations >\n        struct listen_if_pending_transmit_data_is_part_of_any_configuration\n        {\n            using type = std::true_type;\n        };\n\n        template < typename ... Configurations >\n        class peripheral_latency_state< peripheral_latency_configuration_set< Configurations... > >\n            : public connection_state_base< peripheral_latency_state< peripheral_latency_configuration_set< Configurations... > > >\n            , public disarmable_connection_state<\n                        typename listen_if_pending_transmit_data_is_part_of_any_configuration< Configurations... >::type,\n                        peripheral_latency_state< peripheral_latency_configuration_set< Configurations... > > >\n        {\n        public:\n            static_assert( sizeof...(Configurations) > 0, \"At least on configuration is required!\" );\n\n            /**\n             * @brief default configuration, that sets the choosen configuration to the first given.\n             */\n            peripheral_latency_state()\n                : current_configuration_( 0 )\n            {\n            }\n\n            template < class Radio >\n            bool reschedule_on_pending_data( Radio& radio, delta_time connection_iterval )\n            {\n                return this->reschedule_on_pending_data_impl( radio, connection_iterval );\n            }\n\n            template < typename NewConfig >\n            void change_peripheral_latency()\n            {\n                using new_index = bluetoe::details::index_of< NewConfig, Configurations... >;\n                static_assert( new_index::value < sizeof...( Configurations ), \"given NewConfig is not member of Configurations...\" );\n\n                current_configuration_ = new_index::value;\n            }\n\n            template < peripheral_latency RequestedFeature >\n            bool peripheral_latency_feature() const;\n\n        private:\n            template < peripheral_latency RequestedFeature >\n            bool runtime_feature() const;\n\n            int current_configuration_;\n        };\n\n        template < peripheral_latency RequestedFeature, typename Configuration >\n        struct has_feature_enabled_impl;\n\n        template < peripheral_latency RequestedFeature, peripheral_latency ...Options >\n        struct has_feature_enabled_impl< RequestedFeature, peripheral_latency_configuration< Options... > >\n        {\n            static constexpr bool value = feature_enabled< RequestedFeature, Options... >::value;\n        };\n\n\n        template < peripheral_latency RequestedFeature, typename ... Configurations >\n        struct is_part_of_all_configurations\n        {\n            template < typename Configuration >\n            using has_feature_enabled = has_feature_enabled_impl< RequestedFeature, Configuration >;\n\n            static constexpr bool value =\n                bluetoe::details::count_if<\n                    std::tuple< Configurations... >,\n                    has_feature_enabled\n                >::value == sizeof...( Configurations );\n        };\n\n        template < peripheral_latency RequestedFeature, typename ... Configurations >\n        struct is_part_of_no_configurations\n        {\n            template < typename Configuration >\n            using has_feature_enabled = has_feature_enabled_impl< RequestedFeature, Configuration >;\n\n            static constexpr bool value =\n                bluetoe::details::count_if<\n                    std::tuple< Configurations... >,\n                    has_feature_enabled\n                >::value == 0;\n        };\n\n        template < typename ... Configurations >\n        template < peripheral_latency RequestedFeature >\n        bool peripheral_latency_state< peripheral_latency_configuration_set< Configurations... > >::peripheral_latency_feature() const\n        {\n            // if the feature is set in all or none of the Configurations, the test can be done at compile time\n            // and the compiler has a chance to detect dead code\n            if ( is_part_of_all_configurations< RequestedFeature, Configurations... >::value )\n                return true;\n\n            if ( is_part_of_no_configurations< RequestedFeature, Configurations... >::value )\n                return false;\n\n            return runtime_feature< RequestedFeature >();\n        }\n\n        template < peripheral_latency RequestedFeature >\n        struct peripheral_latency_feature_checker\n        {\n            inline explicit peripheral_latency_feature_checker( int config )\n                : index( config )\n                , result( false )\n            {\n            }\n\n            template< typename Config >\n            void each()\n            {\n                if ( index == 0 && has_feature_enabled_impl< RequestedFeature, Config >::value )\n                    result = true;\n\n                --index;\n            }\n\n            int index;\n            bool result;\n        };\n\n        template < typename ... Configurations >\n        template < peripheral_latency RequestedFeature >\n        bool peripheral_latency_state< peripheral_latency_configuration_set< Configurations... > >::runtime_feature() const\n        {\n            peripheral_latency_feature_checker< RequestedFeature > check_feature( current_configuration_ );\n\n            bluetoe::details::for_< Configurations... >::\n                template each< peripheral_latency_feature_checker< RequestedFeature >& >( check_feature );\n\n            return check_feature.result;\n        }\n    }\n}\n}\n\n#endif\n"
  },
  {
    "path": "bluetoe/link_layer/include/bluetoe/phy_encodings.hpp",
    "content": "#ifndef BLUETOE_LINK_LAYER_PHY_ENCODINGS_HPP\n#define BLUETOE_LINK_LAYER_PHY_ENCODINGS_HPP\n\nnamespace bluetoe {\nnamespace link_layer {\n\n    namespace phy_ll_encoding {\n        enum phy_ll_encoding_t : std::uint8_t {\n            le_unchanged_coding = 0x00,\n            le_1m_phy           = 0x01,\n            le_2m_phy           = 0x02,\n            le_coded_phy        = 0x04,\n        };\n    }\n}\n}\n\n#endif\n"
  },
  {
    "path": "bluetoe/link_layer/include/bluetoe/ring_buffer.hpp",
    "content": "#ifndef BLUETOE_LINK_LAYER_RING_BUFFER_HPP\n#define BLUETOE_LINK_LAYER_RING_BUFFER_HPP\n\n#include <cstdint>\n#include <cassert>\n#include <cstdlib>\n\n#include <bluetoe/buffer.hpp>\n#include <bluetoe/default_pdu_layout.hpp>\n\nnamespace bluetoe {\nnamespace link_layer {\n\n    /**\n     * @brief structure, able to store variable sized link layer PDUs in a fixed size ring.\n     *\n     * The buffer uses the size field of the stored PDUs as pointers\n     * to the next PDU stored in the buffer.\n     *\n     * Elements are inserted at the front and removed from the end. When the ring buffer is empty\n     * it is garantied that the buffer can store one elemente of at least Size - 1 in size.\n     *\n     * The Layout is used to access the header field of the PDU and to determin the in memory\n     * length of stored PDUs.\n     */\n    template < std::size_t Size, typename Buffer = read_buffer, typename Layout = default_pdu_layout >\n    class pdu_ring_buffer\n    {\n    public:\n        /**\n         * @brief the size of the buffer in bytes\n         */\n        static constexpr std::size_t size = Size;\n\n        /**\n         * @brief sets up the ring to be empty\n         * @pre next_end().size == 0\n         * @pre buffer must point to an array of at least Size bytes\n         */\n        explicit pdu_ring_buffer( std::uint8_t* buffer );\n\n        /**\n         * @brief resets the ring to be empty\n         * @pre next_end().size == 0\n         * @pre buffer must point to an array of at least Size bytes\n         */\n        void reset( std::uint8_t* buffer );\n\n        /**\n         * @brief return a writeable PDU buffer of at least size bytes at the front of the ring\n         *\n         * The function is idempotent and will yield the same results as long as the state of the\n         * buffer is not changed and the parameters are the same.\n         *\n         * If there is not enough room for size bytes in the ring buffer, the function will return an\n         * empty read_buffer.\n         *\n         * @pre size > Layout::data_channel_pdu_memory_size( 0 )\n         * @pre buffer must point to an array of at least Size bytes\n         */\n        Buffer alloc_front( std::uint8_t* buffer, std::size_t size ) const;\n\n        /**\n         * @brief stores the allocated PDU in the ring.\n         *\n         * The length field of the PDU must contain the actual size of the PDU - 2.\n         * Now the stored PDU can be read through the ring.\n         *\n         * @pre pdu.size >= Layout::data_channel_pdu_memory_size( Layout::header( pdu ) >> 8 )\n         * @pre Layout::header( pdu ) >> 8 != 0\n         * @post next_end().size != 0\n         */\n        void push_front( std::uint8_t* buffer, const Buffer& pdu );\n\n        /**\n         * @brief returns the next PDU from the ring.\n         *\n         * If no PDU is stored in the ring, the function will return an empty write_buffer.\n         */\n        Buffer next_end() const;\n\n        /**\n         * @brief frees the last PDU at the end of the ring\n         *\n         * @pre next_end().size == 0\n         */\n        void pop_end( std::uint8_t* buffer );\n\n        /**\n         * @brief returns true, if the buffer contains at least 2 elements\n         */\n        bool more_than_one() const;\n\n    private:\n        static constexpr std::size_t    ll_header_size = 2;\n        static constexpr std::uint16_t  wrap_mark = 0;\n\n        template < class P >\n        static std::uint8_t pdu_length( const P& pdu );\n\n        template < typename P >\n        static std::size_t pdu_length( P* );\n\n        // 1) if end_ == front_, the ring is empty\n        //        end_ and front_ can point to everywhere into the buffer\n        // 2) if front_ > end_, the all elements are between front_ and end_\n        // 3) if end_ > front_, -> buffer splited\n        //        there are elements from front_ to the end of the buffer\n        //        and there are elements from the beginning of the buffer till end_\n        std::uint8_t* end_;\n        std::uint8_t* front_;\n    };\n\n    template < std::size_t Size, typename Buffer, typename Layout >\n    pdu_ring_buffer< Size, Buffer, Layout >::pdu_ring_buffer( std::uint8_t* buffer )\n    {\n        reset( buffer );\n    }\n\n    template < std::size_t Size, typename Buffer, typename Layout >\n    void pdu_ring_buffer< Size, Buffer, Layout >::reset( std::uint8_t* buffer )\n    {\n        assert( buffer );\n        front_ = buffer;\n        end_   = buffer;\n\n        Layout::header( buffer, wrap_mark );\n    }\n\n    template < std::size_t Size, typename Buffer, typename Layout >\n    Buffer pdu_ring_buffer< Size, Buffer, Layout >::alloc_front( std::uint8_t* buffer, std::size_t size ) const\n    {\n        assert( buffer );\n        assert( size >= Layout::data_channel_pdu_memory_size( 0 ) );\n\n        // buffer splited? There must be one byte left to not overflow the ring.\n        if ( end_ > front_ && static_cast< std::ptrdiff_t >( size ) < end_ - front_ )\n        {\n            return Buffer{ front_, size };\n        }\n\n        if ( front_ >= end_ )\n        {\n            const std::uint8_t* end_of_buffer = buffer + Size;\n\n            // allocate at the end?\n            if ( static_cast< std::ptrdiff_t >( size ) <= end_of_buffer - front_ )\n            {\n                return Buffer{ front_, size };\n            }\n\n            // allocate at the begining? Again, there must be one byte left between the end front_ and the end_\n            if ( static_cast< std::ptrdiff_t >( size ) < end_ - buffer )\n            {\n                return Buffer{ buffer, size };\n            }\n        }\n\n        return Buffer{ 0, 0 };\n    }\n\n    template < std::size_t Size, typename Buffer, typename Layout >\n    void pdu_ring_buffer< Size, Buffer, Layout >::push_front( std::uint8_t* buffer, const Buffer& pdu )\n    {\n        assert( pdu.size >= pdu_length( pdu ) );\n\n        const std::uint8_t* end_of_buffer = buffer + Size;\n\n        // set size to 0 to mark force the end_ pointer to wrap here\n        if ( front_ != pdu.buffer && front_ + 1 < end_of_buffer )\n        {\n            Layout::header( front_, wrap_mark );\n        }\n\n        const bool was_empty = front_ == end_;\n\n        front_ = pdu.buffer + pdu_length( pdu );\n\n        // if the ring was empty, the end_ ptr have to wrap too now\n        if ( was_empty )\n            end_ = pdu.buffer;\n    }\n\n    template < std::size_t Size, typename Buffer, typename Layout >\n    Buffer pdu_ring_buffer< Size, Buffer, Layout >::next_end() const\n    {\n        return front_ == end_\n            ? Buffer{ 0, 0 }\n            : Buffer{ end_, pdu_length( end_ ) };\n    }\n\n    template < std::size_t Size, typename Buffer, typename Layout >\n    void pdu_ring_buffer< Size, Buffer, Layout >::pop_end( std::uint8_t* buffer )\n    {\n        end_ += pdu_length( end_ );\n\n        const std::uint8_t* end_of_buffer = buffer + Size;\n\n        // wrap the end_ pointer to the beginning, if the buffer is not empty\n        if ( end_ != front_ && ( end_ + 1 >= end_of_buffer || end_[ 1 ] == wrap_mark ) )\n            end_ = buffer;\n    }\n\n    template < std::size_t Size, typename Buffer, typename Layout >\n    template < class P >\n    std::uint8_t pdu_ring_buffer< Size, Buffer, Layout >::pdu_length( const P& pdu )\n    {\n        return pdu_length( pdu.buffer );\n    }\n\n    template < std::size_t Size, typename Buffer, typename Layout >\n    template < typename P >\n    std::size_t pdu_ring_buffer< Size, Buffer, Layout >::pdu_length( P* p )\n    {\n        return Layout::data_channel_pdu_memory_size( Layout::header( p ) >> 8 );\n    }\n\n    template < std::size_t Size, typename Buffer, typename Layout >\n    bool pdu_ring_buffer< Size, Buffer, Layout >::more_than_one() const\n    {\n        return end_ != front_ && ( end_ + pdu_length( end_) ) != front_;\n    }\n\n}\n}\n\n#endif\n"
  },
  {
    "path": "bluetoe/link_layer/include/bluetoe/white_list.hpp",
    "content": "#ifndef BLUETOE_LINK_LAYER_WHITE_LIST_HPP\n#define BLUETOE_LINK_LAYER_WHITE_LIST_HPP\n\n#include <bluetoe/address.hpp>\n#include <bluetoe/ll_meta_types.hpp>\n\n#include <iterator>\n#include <algorithm>\n\nnamespace bluetoe {\nnamespace link_layer {\n\n    namespace details {\n        struct white_list_meta_type {};\n\n        template < std::size_t RequiredSize, bool SoftwareRequired, typename Radio, typename LinkLayer >\n        class white_list_implementation;\n    }\n\n    /**\n     * @brief adds a white list to the link layer with white list related functions.\n     *\n     * @tparam Size the maximum number of device addresses, the white list will contain.\n     *\n     * @note the functions is_connection_request_in_filter() and is_scan_request_in_filter() might\n     *       return always true, for a hardware implementation and the hardware would then not\n     *       call the receive callback for devices that are not within the white list.\n     */\n    template < std::size_t Size = 8 >\n    class white_list\n    {\n    public:\n        /** @cond HIDDEN_SYMBOLS */\n        // this functions are purly for documentation purpose, the used implementations is in details::white_list_implementation\n        /** @endcond */\n\n        /**\n         * @brief The maximum number of device addresses, the white list can contain.\n         */\n        static constexpr std::size_t maximum_white_list_entries = Size;\n\n        /**\n         * @brief add the given address to the white list.\n         *\n         * Function will return true, if it was possible to add the address to the white list\n         * or if the address was already in the white list.\n         * If there was not enough room to add the address to the white list, the function\n         * returns false.\n         */\n        bool add_to_white_list( const device_address& addr );\n\n        /**\n         * @brief remove the given address from the white list\n         *\n         * The function returns true, if the address was in the list.\n         * @post addr is not in the white list.\n         */\n        bool remove_from_white_list( const device_address& addr );\n\n        /**\n         * @brief returns true, if the given address in within the white list\n         */\n        bool is_in_white_list( const device_address& addr ) const;\n\n        /**\n         * @brief returns the number of addresses that could be added to the\n         *        white list before add_to_white_list() would return false.\n         */\n        std::size_t white_list_free_size() const;\n\n        /**\n         * @brief remove all entries from the white list\n         */\n        void clear_white_list();\n\n        /**\n         * @brief Accept connection requests only from devices within the white list.\n         *\n         * If the property is set to true, only connection requests from from devices\n         * that are in the white list, should be answered.\n         * If the property is set to false, all connection requests should be answered.\n         *\n         * The default value of the is property is false.\n         *\n         * @post connection_request_filter() == b\n         * @sa connection_request_filter()\n         */\n        void connection_request_filter( bool b );\n\n        /**\n         * @brief current value of the property.\n         */\n        bool connection_request_filter() const;\n\n        /**\n         * @brief Accept scan requests only from devices within the white list.\n         *\n         * If the property is set to true, only scan requests from from devices\n         * that are in the white list, should be answered.\n         * If the property is set to false, all scan requests should be answered.\n         *\n         * The default value of the is property is false.\n         *\n         * @post scan_request_filter() == b\n         * @sa scan_request_filter()\n         */\n        void scan_request_filter( bool b );\n\n        /**\n         * @brief current value of the property.\n         */\n        bool scan_request_filter() const;\n\n        /**\n         * @brief returns true, if a connection request from the given address should be answered.\n         */\n        bool is_connection_request_in_filter( const device_address& addr ) const;\n\n        /**\n         * @brief returns true, if a scan request from the given address should be answered.\n         */\n        bool is_scan_request_in_filter( const device_address& addr ) const;\n\n        /** @cond HIDDEN_SYMBOLS */\n        struct meta_type :\n            details::white_list_meta_type,\n            details::valid_link_layer_option_meta_type {};\n\n        template < class Radio, class LinkLayer >\n        struct impl :\n            details::white_list_implementation<\n                Size,\n                ( Size > Radio::radio_maximum_white_list_entries ),\n                Radio,\n                LinkLayer\n            >\n        {\n        };\n        /** @endcond */\n    };\n\n    /**\n     * @brief no white list in the link layer\n     *\n     * This is the default\n     */\n    struct no_white_list {\n        /** @cond HIDDEN_SYMBOLS */\n        template < class Radio, class LinkLayer >\n        struct impl {\n            bool is_connection_request_in_filter( const device_address& ) const\n            {\n                return true;\n            }\n\n            bool is_scan_request_in_filter( const device_address& ) const\n            {\n                return true;\n            }\n        };\n\n        struct meta_type :\n            details::white_list_meta_type,\n            details::valid_link_layer_option_meta_type {};\n        /** @endcond */\n    };\n\n    namespace details {\n\n        /**\n         * pure software implementation\n         */\n        template < std::size_t Size, typename Radio, typename LinkLayer >\n        class white_list_implementation< Size, true, Radio, LinkLayer >\n        {\n        public:\n            static constexpr std::size_t maximum_white_list_entries = Size;\n\n            white_list_implementation()\n                : active_( false )\n                , free_size_( Size )\n                , connection_filter_( false )\n                , scan_filter_( false )\n            {\n            }\n\n            std::size_t white_list_free_size() const\n            {\n                return free_size_;\n            }\n\n            void clear_white_list()\n            {\n                free_size_ = Size;\n            }\n\n            bool add_to_white_list( const device_address& addr )\n            {\n                if ( is_in_white_list( addr ) )\n                    return true;\n\n                if ( free_size_ == 0 )\n                    return false;\n\n                addresses_[ Size - free_size_ ] = addr;\n                --free_size_;\n                return true;\n            }\n\n            bool is_in_white_list( const device_address& addr ) const\n            {\n                const auto end = std::begin( addresses_ ) + ( Size - free_size_ );\n                return std::find( std::begin( addresses_ ), end, addr ) != end;\n            }\n\n            bool remove_from_white_list( const device_address& addr )\n            {\n                const auto end = std::begin( addresses_ ) + ( Size - free_size_ );\n                const auto pos = std::find( std::begin( addresses_ ), end, addr );\n\n                if ( pos == end )\n                    return false;\n\n                *pos = *( end - 1 );\n                ++free_size_;\n\n                return true;\n            }\n\n            void connection_request_filter( bool b )\n            {\n                connection_filter_ = b;\n            }\n\n            bool connection_request_filter() const\n            {\n                return connection_filter_;\n            }\n\n            void scan_request_filter( bool b )\n            {\n                scan_filter_ = b;\n            }\n\n            bool scan_request_filter() const\n            {\n                return scan_filter_;\n            }\n\n            bool is_connection_request_in_filter( const device_address& addr ) const\n            {\n                return !connection_filter_ || is_in_white_list( addr );\n            }\n\n            bool is_scan_request_in_filter( const device_address& addr ) const\n            {\n                return !scan_filter_ || is_in_white_list( addr );\n            }\n\n        private:\n            bool            active_;\n            std::size_t     free_size_;\n            device_address  addresses_[ Size ];\n            bool            connection_filter_;\n            bool            scan_filter_;\n        };\n\n        /**\n         * Hardware only implemenation\n         */\n        template < std::size_t Size, typename Radio, typename LinkLayer >\n        class white_list_implementation< Size, false, Radio, LinkLayer >\n        {\n        public:\n            static constexpr std::size_t maximum_white_list_entries = Size;\n\n            std::size_t white_list_free_size() const\n            {\n                return this_to_radio().radio_white_list_free_size();\n            }\n\n            void clear_white_list()\n            {\n                this_to_radio().radio_clear_white_list();\n            }\n\n            bool add_to_white_list( const device_address& addr )\n            {\n                return this_to_radio().radio_add_to_white_list( addr );\n            }\n\n            bool is_in_white_list( const device_address& addr ) const\n            {\n                return this_to_radio().radio_is_in_white_list( addr );\n            }\n\n            bool remove_from_white_list( const device_address& addr )\n            {\n                return this_to_radio().radio_remove_from_white_list( addr );\n            }\n\n            void connection_request_filter( bool b )\n            {\n                this_to_radio().radio_connection_request_filter( b );\n            }\n\n            bool connection_request_filter() const\n            {\n                return this_to_radio().radio_connection_request_filter();\n            }\n\n            void scan_request_filter( bool b )\n            {\n                this_to_radio().radio_scan_request_filter( b );\n            }\n\n            bool scan_request_filter() const\n            {\n                return this_to_radio().radio_scan_request_filter();\n            }\n\n            bool is_connection_request_in_filter( const device_address& addr ) const\n            {\n                return this_to_radio().radio_is_connection_request_in_filter( addr );\n            }\n\n            bool is_scan_request_in_filter( const device_address& addr ) const\n            {\n                return this_to_radio().radio_is_scan_request_in_filter( addr );\n            }\n        private:\n            Radio& this_to_radio()\n            {\n                return static_cast< Radio& >( static_cast< LinkLayer& >( *this ) );\n            }\n\n            const Radio& this_to_radio() const\n            {\n                return static_cast< const Radio& >( static_cast< const LinkLayer& >( *this ) );\n            }\n        };\n    }\n}\n}\n#endif\n"
  },
  {
    "path": "bluetoe/link_layer/scheduled_radio.hpp",
    "content": "#ifndef BLUETOE_LINK_LAYER_SCHEDULED_RADIO_HPP\n#define BLUETOE_LINK_LAYER_SCHEDULED_RADIO_HPP\n\n#include <cstdint>\n#include <buffer.hpp>\n#include <address.hpp>\n#include <ll_data_pdu_buffer.hpp>\n\nnamespace bluetoe {\nnamespace link_layer {\n\n    class delta_time;\n    class write_buffer;\n    class read_buffer;\n\n    /**\n     * @brief Type responsible for radio I/O and timing\n     *\n     * The API provides a set of scheduling functions, to schedule advertising or to schedule connection events. All scheduling functions take a point in time\n     * to switch on the receiver / transmitter and to transmit and to receive. This points are defined as relative offsets to a previous point in time T0. The\n     * first T0 is defined by the return of the constructor. After that, every scheduling function have to define what the next T0 is, that the next\n     * functions relative point in time, is based on.\n     *\n     * TransmitSize and ReceiveSize is the size of buffer used for receiving and transmitting. This might not make sense for all implementations.\n     */\n    template < std::size_t TransmitSize, std::size_t ReceiveSize, typename CallBack >\n    class scheduled_radio : public ll_data_pdu_buffer< TransmitSize, ReceiveSize, scheduled_radio< TransmitSize, ReceiveSize, CallBack > >\n    {\n    public:\n        /**\n         * initializes the hardware and defines the first time point as anker for the next call to a scheduling function.\n         */\n        scheduled_radio();\n\n        /**\n         * @brief schedules for transmission of advertising data and starts to receive 150µs later\n         *\n         * The function will return immediately. Depending on whether a response is received or the receiving times out,\n         * CallBack::adv_received() or CallBack::adv_timeout() is called. In both cases, every following call to a scheduling\n         * function is based on the time, the transmission was scheduled. So the new T0 = T0 + when. In case of a CRC error,\n         * CallBack::adv_timeout() will be called immediately.\n         *\n         * White list filtering is applied by calling CallBack::is_scan_request_in_filter().\n         *\n         * This function is intended to be used for sending advertising PDUs.\n         *\n         * @param channel channel to transmit and to receive on\n         * @param advertising_data the advertising data to be send out.\n         * @param response_data the response data used to reply to a scan request, in case the request was in the white list.\n         * @param when point in time, when the first bit of data should be started to be transmitted\n         * @param receive buffer where the radio will copy the received data, before calling Callback::adv_receive().\n         *        This buffer have to have at least room for two bytes.\n         */\n        void schedule_advertisment(\n            unsigned                                    channel,\n            const bluetoe::link_layer::write_buffer&    advertising_data,\n            const bluetoe::link_layer::write_buffer&    response_data,\n            bluetoe::link_layer::delta_time             when,\n            const bluetoe::link_layer::read_buffer&     receive );\n\n        /**\n         * @brief schedules a connection event\n         *\n         * The function will return immediately and schedule the receiver to start at start_receive.\n         *\n         * CallBack::timeout() is called when between start_receive and end_receive no valid pdu is received.\n         * The new T0 is then the old T0.\n         *\n         * CallBack::end_event(connection_event_event evts) is called when\n         * the connection event is over. The evts object passed to the end_event() callback will give\n         * some details about what happend in that connection event.\n         * The new T0 is the time point where the first PDU was received from the central.\n         *\n         * In any case is one (and only one) of the callbacks called (timeout(), end_event()), unless the connection event\n         * is disarmed prior, by a call to disarm_connection_event(). The context of the callback call is run().\n         *\n         * Data to be transmitted and received is passed by the inherited ll_data_pdu_buffer.\n         *\n         * @return the distance from now to start_receive. If the scheduled event is already in the past,\n         *         the function will return delta_time() and the timeout() callback will be called.\n         */\n        bluetoe::link_layer::delta_time schedule_connection_event(\n            unsigned                                    channel,\n            bluetoe::link_layer::delta_time             start_receive,\n            bluetoe::link_layer::delta_time             end_receive,\n            bluetoe::link_layer::delta_time             connection_interval );\n\n        /**\n         * @brief tries to stop a scheduled connection event\n         *\n         * The function tries to stop the scheduled connection event if it is not already\n         * running, already in the past or too close to happen to be canceled.\n         *\n         * If the function was able to stop the connection event, it will return true and the current\n         * time from the last anchor plus some margin that is used by schedule_connection_event()\n         * to make sure, that the connection event can be setup before reaching the start time.\n         *\n         * The support for this function is optional. If a scheduled_radio implementation does not\n         * implement this function, there will be no support for the peripheral latency option:\n         * peripheral_latency::listen_if_pending_transmit_data\n         */\n        std::pair< bool, bluetoe::link_layer::delta_time > disarm_connection_event();\n\n        /**\n         * @brief sets up a timer\n         *\n         * The timeout is based on the connects last anchor. Which then means, that there\n         * has to be a connection and that the anchor will not move, if there was a timeout\n         * while waiting for the next connection event.\n         *\n         * Calls CallBack::user_timer( bool anchor_moved ) from an unspecified CPU context.\n         * anchor_moved is set to true, if the anchor moved inbetween setting up the timer\n         * and the timer callback beeing called.\n         */\n        bool schedule_synchronized_user_timer(\n            bluetoe::link_layer::delta_time timeout,\n            bluetoe::link_layer::delta_time max_cb_runtime );\n\n        /**\n         * @brief cancel the user timer\n         */\n        bool cancel_synchronized_user_timer();\n\n        /**\n         * @brief set the access address initial CRC value for transmitted and received PDU\n         *\n         * The values should be changed, when there is no outstanding scheduled transmission or receiving.\n         * The values will be applied with the next call to schedule_advertisment() or schedule_connection_event().\n         */\n        void set_access_address_and_crc_init( std::uint32_t access_address, std::uint32_t crc_init );\n\n        /**\n         * @brief function to return a device specific value that is persistent and unique for the device (CPU id or such)\n         */\n        std::uint32_t static_random_address_seed() const;\n\n        /**\n         * @brief allocates the CPU to the scheduled_radio\n         *\n         * All callbacks given by the CallBack parameter are called from within this CPU context.\n         * The function will return from time to time, when an external event happed. It's up to concrete\n         * implementations to identify and to define situations where the CPU should be released back to the\n         * calling application.\n         */\n        void run();\n\n        /**\n         * @brief forces the run() function to return at least once\n         *\n         * The function is intended to be used from interrupt handler to synchronize with the main thread.\n         */\n        void wake_up();\n\n        /**\n         * @brief forces the call of CallBack::try_event_cancelation() from the context of the run() function\n         *\n         * The function queues the request until control is passed back to run().\n         *\n         * The function is intended to be used from interrupt handler to synchronize with the main thread.\n         */\n        void request_event_cancelation();\n\n        /**\n         * @brief type to allow ll_data_pdu_buffer to synchronize the access to the buffer data structures.\n         */\n        class lock_guard;\n\n        /**\n         * @brief giving the maximum number of white list entries, the scheduled radio supports by hardware\n         *\n         * Only if this value is not zero, the radio have to implement the white list related functions.\n         */\n        static constexpr std::size_t radio_maximum_white_list_entries = 4;\n\n        /**\n         * @brief add the given address to the white list.\n         *\n         * Function will return true, if it was possible to add the address to the white list\n         * or if the address was already in the white list.\n         * If there was not enough room to add the address to the white list, the function\n         * returns false.\n         */\n        bool radio_add_to_white_list( const device_address& addr );\n\n        /**\n         * @brief remove the given address from the white list\n         *\n         * The function returns true, if the address was in the list.\n         * @post addr is not in the white list.\n         */\n        bool radio_remove_from_white_list( const device_address& addr );\n\n        /**\n         * @brief returns true, if the given address in within the white list\n         */\n        bool radio_is_in_white_list( const device_address& addr ) const;\n\n        /**\n         * @brief returns the number of addresses that could be added to the\n         *        white list before add_to_white_list() would return false.\n         */\n        std::size_t radio_white_list_free_size() const;\n\n        /**\n         * @brief remove all entries from the white list\n         */\n        void radio_clear_white_list();\n\n        /**\n         * @brief Accept connection requests only from devices within the white list.\n         *\n         * If the property is set to true, only connection requests from from devices\n         * that are in the white list, should be answered.\n         * If the property is set to false, all connection requests should be answered.\n         *\n         * The default value of the is property is false.\n         *\n         * @post connection_request_filter() == b\n         * @sa connection_request_filter()\n         */\n        void connection_request_filter( bool b );\n\n        /**\n         * @brief current value of the property.\n         */\n        bool connection_request_filter() const;\n\n        /**\n         * @brief Accept scan requests only from devices within the white list.\n         *\n         * If the property is set to true, only scan requests from from devices\n         * that are in the white list, should be answered.\n         * If the property is set to false, all scan requests should be answered.\n         *\n         * @post radio_scan_request_filter() == b\n         * @sa radio_scan_request_filter()\n         */\n        void radio_scan_request_filter( bool b );\n\n        /**\n         * @brief current value of the property.\n         */\n        bool radio_scan_request_filter() const;\n\n        /**\n         * @brief returns true, if a connection request from the given address should be answered.\n         */\n        bool radio_is_connection_request_in_filter( const device_address& addr ) const;\n\n        /**\n         * @brief returns true, if a scan request from the given address should be answered.\n         */\n        bool radio_is_scan_request_in_filter( const device_address& addr ) const;\n\n        /**\n         * @brief change the used PHY encoding for the transmitting and receiving side\n         */\n        void radio_set_phy( details::phy_ll_encoding receiving_encoding, details::phy_ll_encoding transmiting_c_encoding );\n\n        /**\n         * @brief a number of bytes that are additional required by the hardware to handle an over the air package/PDU.\n         *\n         * This number includes every byte that have to stored in a package to meet the requirments of the hardware,\n         * that is not part of the received / transmitted PDU (CRC, preamble etc.).\n         */\n        static constexpr std::size_t radio_package_overhead = 0;\n\n        /**\n         * @brief indication no support for encryption\n         */\n        static constexpr bool hardware_supports_encryption = false;\n\n        /**\n         * @brief indicates support for 2Mbit\n         */\n        static constexpr bool hardware_supports_2mbit = true;\n\n        /**\n         * @brief indicates support for schedule_synchronized_user_timer()\n         */\n        static constexpr bool hardware_supports_synchronized_user_timer = true;\n    };\n\n    /**\n     * @brief extension of a scheduled_radio with functions to support encryption\n     *\n     * To allow the utilization of hardware support for certain cryptographical functions,\n     * this interface abstracts at a quite high level.\n     */\n    template < std::size_t TransmitSize, std::size_t ReceiveSize, typename CallBack >\n    class scheduled_radio_with_encryption : public scheduled_radio< TransmitSize, ReceiveSize, CallBack >\n    {\n    public:\n        /**\n         * @brief indicates the support for LESC pairing\n         */\n        static constexpr bool hardware_supports_lesc_pairing = false;\n\n        /**\n         * @brief indicates the support for legacy pairing\n         */\n        static constexpr bool hardware_supports_legacy_pairing = true;\n\n        /**\n         * @brief indication no support for encryption\n         */\n        static constexpr bool hardware_supports_encryption = hardware_supports_lesc_pairing || hardware_supports_legacy_pairing;\n\n        /**\n         * @brief Function to create the Srand according to 2.3.5.5 Part H, Vol 3, Core Spec\n         */\n        bluetoe::details::uint128_t create_srand();\n\n        /**\n         * @brief Function to create a random long term key and random Rand and EDIV values to identify this newly created key.\n         */\n        bluetoe::details::longterm_key_t create_long_term_key();\n\n        /**\n         * @brief Confirm value generation function c1 for LE Legacy Pairing\n         *\n         * @param temp_key the temporary key from the LE legacy pairing algorithm\n         * @param rand the value created by create_srand() or the\n         * @param p1 p1 = pres || preq || rat’ || iat’ (see 2.3.3 Confirm value generation function c1 for LE Legacy Pairing)\n         * @param p2 p2 = padding || ia || ra (see 2.3.3 Confirm value generation function c1 for LE Legacy Pairing)\n         *\n         * The function calculates the confirm value based on the peripherals or centrals random value (Srand or Mrand), the temporary\n         * key and the data in the pairing request and response.\n         */\n        bluetoe::details::uint128_t c1(\n            const bluetoe::details::uint128_t& temp_key,\n            const bluetoe::details::uint128_t& rand,\n            const bluetoe::details::uint128_t& p1,\n            const bluetoe::details::uint128_t& p2 ) const;\n\n        /**\n         * @brief Key generation function s1 for LE Legacy Pairing\n         *\n         * The key generation function s1 is used to generate the STK during the LE\n         * legacy pairing process.\n         *\n         * @param temp_key the temporary key from the LE legacy pairing algorithm\n         * @param prand The peripheral random value (Prand).\n         * @param crand The central random value (Crand).\n         */\n        bluetoe::details::uint128_t s1(\n            const bluetoe::details::uint128_t& temp_key,\n            const bluetoe::details::uint128_t& prand,\n            const bluetoe::details::uint128_t& crand );\n\n        /**\n         * @brief setup the hardware with all data required for encryption\n         *\n         * The encryption is prepaired but not started jet.\n         * @param key long term or short term key to be used for encryption\n         * @param skdm The central's portion of the session key diversifier.\n         * @param ivm The IVm field contains the central portion of the initialization vector.\n         *\n         * The function returns SKDs and IVs (the peripherals portion of the session key diversifier and initialization vector),\n         * to be send to the central.\n         */\n        std::pair< std::uint64_t, std::uint32_t > setup_encryption( bluetoe::details::uint128_t key, std::uint64_t skdm, std::uint32_t ivm );\n\n        /**\n         * features required for LESC\n         */\n        bool is_valid_public_key( const std::uint8_t* public_key ) const;\n\n        /**\n         * @brief generate public private key pair for DH\n         */\n        std::pair< bluetoe::details::ecdh_public_key_t, bluetoe::details::ecdh_private_key_t > generate_keys();\n\n        /**\n         * @brief random nonce required for LESC pairing\n         */\n        bluetoe::details::uint128_t select_random_nonce();\n\n        /**\n         * @brief p256() security toolbox function, as specified in the core spec\n         */\n        bluetoe::details::ecdh_shared_secret_t p256( const std::uint8_t* private_key, const std::uint8_t* public_key );\n\n        /**\n         * @brief f4() security toolbox function, as specified in the core spec\n         */\n        bluetoe::details::uint128_t f4( const std::uint8_t* u, const std::uint8_t* v, const std::array< std::uint8_t, 16 >& k, std::uint8_t z );\n\n        /**\n         * @brief f5() security toolbox function, as specified in the core spec\n         */\n        std::pair< bluetoe::details::uint128_t, bluetoe::details::uint128_t > f5(\n            const bluetoe::details::ecdh_shared_secret_t dh_key,\n            const bluetoe::details::uint128_t& nonce_central,\n            const bluetoe::details::uint128_t& nonce_periperal,\n            const bluetoe::link_layer::device_address& addr_controller,\n            const bluetoe::link_layer::device_address& addr_peripheral );\n\n        /**\n         * @brief f6() security toolbox function, as specified in the core spec\n         */\n        bluetoe::details::uint128_t f6(\n            const bluetoe::details::uint128_t& key,\n            const bluetoe::details::uint128_t& n1,\n            const bluetoe::details::uint128_t& n2,\n            const bluetoe::details::uint128_t& r,\n            const bluetoe::details::io_capabilities_t& io_caps,\n            const bluetoe::link_layer::device_address& addr_controller,\n            const bluetoe::link_layer::device_address& addr_peripheral );\n\n        /**\n         * @brief g2() security toolbox function, as specified in the core spec\n         */\n        std::uint32_t g2(\n            const std::uint8_t*                 u,\n            const std::uint8_t*                 v,\n            const bluetoe::details::uint128_t&  x,\n            const bluetoe::details::uint128_t&  y );\n\n        /**\n         * Functions required by IO capabilties\n         */\n        bluetoe::details::uint128_t create_passkey();\n\n        /**\n         * @brief start the encryption of received PDUs with the next connection event.\n         */\n        void start_receive_encrypted();\n\n        /**\n         * @brief start to encrypt transmitted PDUs with the next connection event.\n         */\n        void start_transmit_encrypted();\n\n        /**\n         * @brief stop receiving encrypted with the next connection event.\n         */\n        void stop_receive_encrypted();\n\n        /**\n         * @brief stop transmitting encrypted with the next connection event.\n         */\n        void stop_transmit_encrypted();\n    };\n\n    /**\n     * @brief type that provides types and functions to access the differnt parts of a receiving PDU.\n     *\n     * There might be technical reasons, why an in memory PDU might differ in layout from an over the air PDU.\n     * This indirection is supposed to resolve such cases. (Currently, it's nrf51/52 that requires this).\n     *\n     * By default, bluetoe::link_layer::default_pdu_layout is used. To override this for a radio R, specialize\n     * bluetoe::link_layer::pdu_layout_by_radio for R to define an alias to the layout type to be used:\n     *\n     * @code\n     * template <>\n     * struct pdu_layout_by_radio< R > {\n     *     using pdu_layout = special_pdu_layout_required_by_R;\n     * };\n     * @endcode\n     *\n     */\n    struct pdu_layout {\n        /**\n         * @brief returns the header for advertising channel and for data channel PDUs.\n         */\n        static std::uint16_t header( const read_buffer& pdu );\n\n        /**\n         * @brief returns the header for advertising channel and for data channel PDUs.\n         */\n        static std::uint16_t header( const write_buffer& pdu );\n\n        /**\n         * @brief returns the header for advertising channel and for data channel PDUs.\n         */\n        static std::uint16_t header( const std::uint8_t* pdu );\n\n        /**\n         * @brief writes to the header of the given PDU\n         */\n        static void header( const read_buffer& pdu, std::uint16_t header_value );\n\n        /**\n         * @brief writes to the header of the given PDU\n         */\n        static void header( std::uint8_t* pdu, std::uint16_t header_value );\n\n        /**\n         * @brief returns the writable body for advertising channel or for data channel PDUs.\n         */\n        static std::pair< std::uint8_t*, std::uint8_t* > body( const read_buffer& pdu );\n\n        /**\n         * @brief returns the readonly body for advertising channel or for data channel PDUs.\n         */\n        static std::pair< const std::uint8_t*, const std::uint8_t* > body( const write_buffer& pdu );\n\n        /**\n         * @brief returns the size of the memory buffer that is required to keep a data channel PDU\n         *        in memory, with the given payload size (payload according to Vol.6; Part B; 2.4).\n         *\n         * This function have to be constexpr / evaluatable at compile time to allow static buffer\n         * size calculation.\n         */\n        static constexpr std::size_t data_channel_pdu_memory_size( std::size_t payload_size );\n    };\n}\n\n}\n\n#endif // include guard\n"
  },
  {
    "path": "bluetoe/link_state.hpp",
    "content": "#ifndef BLUETOE_LINK_STATE_HPP\n#define BLUETOE_LINK_STATE_HPP\n\n#include <bluetoe/pairing_status.hpp>\n#include <bluetoe/codes.hpp>\n\nnamespace bluetoe {\nnamespace details {\n\n    /**\n     * @brief Attributes of a link\n     *\n     * Data that is required / provided by the link_layer or by any\n     * l2cap layer service (ATT/SM).\n     *\n     * Currently, this state data is required by the link_layer,\n     * the ATT layer (server.hpp) and by the security manager.\n     */\n    class link_state\n    {\n    public:\n        link_state()\n            : encrypted_( false )\n            , pairing_status_( device_pairing_status::no_key )\n        {\n        }\n\n        /**\n         * @brief returns true, if the connection is currently encrypted\n         */\n        bool is_encrypted() const\n        {\n            return encrypted_;\n        }\n\n        /**\n         * @brief set the current encryption status\n         *\n         * Returns true, if the value changed.\n         */\n        bool is_encrypted( bool encrypted )\n        {\n            const bool result = encrypted_ != encrypted;\n            encrypted_ = encrypted;\n\n            return result;\n        }\n\n        /**\n         * @brief returns the pairing state of the local device with the remote device for this link\n         */\n        device_pairing_status pairing_status() const\n        {\n            return pairing_status_;\n        }\n\n        /**\n         * @brief sets the pairing status of the current link / connection\n         */\n        void pairing_status( device_pairing_status status )\n        {\n            pairing_status_ = status;\n        }\n\n        /**\n         * @brief returns the result of is_encrypted() and pairing_status() as tuple\n         */\n        connection_security_attributes security_attributes() const\n        {\n            return connection_security_attributes{ encrypted_, pairing_status_ };\n        }\n\n    private:\n        bool                        encrypted_;\n        device_pairing_status       pairing_status_;\n    };\n\n    /**\n     * @brief in case, no security is implemented on the link layer\n     */\n    class link_state_no_security\n    {\n    public:\n        bool is_encrypted() const\n        {\n            return false;\n        }\n\n        /**\n         * @brief returns the pairing state of the local device with the remote device for this link\n         */\n        device_pairing_status pairing_status() const\n        {\n            return device_pairing_status::no_key;\n        }\n\n        /**\n         * @brief returns the result of is_encrypted() and pairing_status() as tuple\n         */\n        connection_security_attributes security_attributes() const\n        {\n            return connection_security_attributes{ false, device_pairing_status::no_key };\n        }\n    };\n\n}\n}\n\n#endif // include guard\n"
  },
  {
    "path": "bluetoe/mainpage.hpp",
    "content": "/*! @mainpage Bluetoe\n\n@section intro_sec Introduction\n\nBluetoe is an attempt to simplify the implementation of firmware for Bluetooth Low Energy devices. Bluetooth Low Energy devices / peripherals implement a so called GATT Server. GATT is the abreviation of Generic Attribute Profile. GATT is a protocol that allows a computer (desktop, phone etc.) to discover remote devices capabilities and to interact with this devices in an unified manner.\n\nA lot of possible device capabilities are specified by the <a href=\"https://www.bluetooth.org\">Bluetooth Special Interest Group</a>. Others capabilities are user defined and make sense only to the implementer of a device and requires a special client that knows how to use this capabilities. Those capabilities and the means how to access them are called profiles.\n\n@section gatt_basics GATT Basics\n\n@subsection Characteristics\n\nThe basic building blocks of GATT are characteristics. A \\link bluetoe::characteristic characteristic \\endlink can be thinked of as a piece of information / a variable that resides inside of a device, which clients can interact with (discover, reading, writing). To identify a characteristic, an identifier, called a UUID is used. Beside some very basic properties like \"readable\" or \"writeable\", a characteristic can have additional properties like a name or structure informations (e.g. this is a structure containing 1 float followed by 2 integers).\n\n@subsection Services\n\nA \\link bluetoe::service service \\endlink groups characteristics to meaningful units. A helicopter position service would for example group the X, Y, and Z position of the helicopter to a Position Service. A device can announce the implementation / existance of a service by that device, so that computers looking for a specific device can see that the device is implementing the service, without the need to connect to the device.\n\n@subsection Profiles\n\nA profile groups @ref Services to higher level functionality and is usually \"just\" a document that describes what a device must implement to be conforming to a certain profile and how client should interact with services.\n\n@subsection UUIDs\n\nBoth, @ref Characteristics and @ref Services are identified by Universally Unique Identifiers (<a href=\"https://en.wikipedia.org/wiki/Universally_unique_identifier\">UUID</a>). Bluetooth Low Energy basically uses two different kinds of UUIDs, one 16 bit long, the other 128 bit long.\n\n16-bit UUIDs are exclusivly assigned by the <a href=\"https://www.bluetooth.org\">Bluetooth Special Interest Group</a>. 128-bit UUIDs can be generated by anyone and used in custom applications that are not standardised.\n\n16-bit UUIDs are usually notated as a 4 digit hexadecimal number. 128-bit UUIDs are grouped in packs of different size. Example: 7A5F69F4-3915-41C7-92BD-1477B35B883D.\n\n@subsection ATT\n\nGATT is implemented on top of ATT (Attribute Protocol). GATT basecally defines how characteristics and services are mapped to attributes and how GATT procedures are mapped to ATT procedures to access the characteristics and services. A GATT server defines all its services and characterstics with one, single table of attributes.\n\nAn attribute is a tuple, containing a handle, a type, and a value. Where a handle is a 16 bit integer, which is some kind of unique key into an attribute table. The type denoted by a UUID and is either 16 bit or 128 bit long. UUIDs within the attribute table are not unique. Finally, data is a variable length data field, that can be read and / or written.\n\nATT not only defines this attribute table, but also how to access this table. While GATT procedures are the means of how to access the characteristics of a service, what is actually spoken on air (and thus observable or debuggable) is ATT. But this mapping of GATT procedures to ATT procedures is quit leightweigt and easy to understand and intuitive.\n\n@section start_bluetoe Bluetoe's Implementation of GATT\n\nBluetoe let you define a list of GATT services on your own, let you define the characteristics within each service and how accesses to a characteristic are mapped to C++ function calls (or global variables accesses, or constants beeing reads).\n\n@subsection Characteristic\n\nBluetoe uses the C++ type system to collect all data / information that is already available at compile time from the developer. So, the definition of a characteristic is a type; A template class called @ref bluetoe::characteristic which takes a list of parameters that defines how exactly a characteristic should work. Template classes that take a variable list of parameters are often used within Bluetoe and in most cases, the order of the parameters are not important. Here is a minimalistic example:\n\n@code{.cpp}\nusing io_pin_access_characteristic =\n    bluetoe::characteristic<\n        bluetoe::characteristic_uuid< 0x43809849, 0x0025, 0x4529, 0xA50F, 0x48C362742282 >,\n        bluetoe::free_write_handler< bool, io_pin_write_handler >\n    >;\n\n@endcode\n\nThe type definition above, defines a characteristic which is identifed by the 128 bit UUID 43809849-0025-4529-A50F-48C362742282 and defines, which free function have to be called, in case that there is any write attempt to the characteristic.\n\nBy omitting a definition of how to read the characteristic, bluetoe assumes that the characteristic is write-only. Any attempt to read the characteristic will be responded with an error.\n\nFurthermore, by defing bool, to be the type, that is taken by the write handler (io_pin_write_handler()), Bluetoe will generate error responses to every attempt to write othere values that are not a single byte containing the value 1 or 0.\n\nSo the signature of io_pin_write_handler() looks like this:\n\n@code{.cpp}\nstd::uint8_t io_pin_write_handler( bool state );\n@endcode\n\nThe return values allows the handler to return errors, in case the requested write caused any error.\n\nAnd that's all, Bluetoe needs to know to implement the access of the write-only characteristic that accepts only boolean values. Bluetoe will use this information to generate the necessary attributes in the ATT attribute table, to handle the very basic error cases and to map the characteristic access to a specific handler. No need to define handles, no need to define characteristic attributes, nor characteristic descriptors.\n\nThis shows some of the key design decisions, made for Bluetoe:\n- No need to provide redundant information: No need to specify characteristic attributes, which is done implicit by the defined read and write handlers. No need to assigned handles or define descriptors, which is done by the library.\n- Safe and resonable defaults are used: By narrowing down, the accepted range of values, by defining the type of stored information, Bluetoe can handle already a lot of malicious write attempts that do not fit to the underlying data type.\n- Find as much bugs as possible at compile time: For example: defining a characteristic, that has neither a read handler, nor a write handler defined, will result in a compile time error.\n- Make easy things easy: There should not be any need to read the bluetooth core specification before being able to read and understand the libraries documentation and there concepts.\n\nHere is a second example of a characteristic definition:\n\n@code{.cpp}\nusing temperature_characteristic =\n    bluetoe::characteristic<\n        bluetoe::characteristic_uuid< 0x8C8B4094, 0x0DE2, 0x499F, 0xA28A, 0x4EED5BC73CA9 >,\n        bluetoe::bind_characteristic_value< decltype( temperature ), &temperature >,\n        bluetoe::no_write_access\n    >;\n@endcode\n\nThis time, accessing the characteristic, is mapped to a global variable named temperature, by using the @ref bluetoe::bind_characteristic_value template, that takes a variable type and the address of a variable.\n\nThis would make Bluetoe to generate code that allows to read and write the characteristic value, as long as the size of the data written has the size of the given type. By adding the type @ref bluetoe::no_write_access parameter, Bluetoe will remove the write access to the characteristic and will respond with an error code to every attempt to write to the characteristic.\n\nThere are a lot more types that defines the binding to characteristic values.\n\n@subsection Service\n\nRoughly saying, a @ref bluetoe::service is just an UUID with a list of characteristics! So this example should make sense to you:\n\n@code{.cpp}\nusing temperature_and_io_pin_service =\n    bluetoe::service<\n        bluetoe::service_uuid< 0xC11169E1, 0x6252, 0x4450, 0x931C, 0x1B43A318783B >,\n        io_pin_access_characteristic,\n        temperature_characteristic\n    >;\n@endcode\n\nThis service somehow combines the reading of a temperatur and the setting of an IO pin. Maybe the IO pin is connected to an actor, that can open or close a window and thus influence the temperature.\n\n@subsection Server\n\nFinally a @ref bluetoe::server combines all @ref bluetoe::service to implement a GATT server:\n\n@code{.cpp}\nusing gatt_server =\n    bluetoe::server<\n       temperature_and_io_pin_service\n    >;\n@endcode\n\nThis is a very minimalistic example. A more sophisticated example would take serveral services and would give the server a name and such details. Bluetoe already applies a lot of defaults. A @ref bluetoe::gap_service_for_gatt_servers is added by default to the server.\n\n@section hardware_binding Binding to Hardware\n\nUp to now, there is no actual hardware involved. To deploy a defined GATT server to specific hardware, a so called binding is used, that takes the @ref bluetoe::server instance as parameter. Here an example that uses a nrf52 from Nordic as target hardware:\n\n@code{.cpp}\n\nbluetoe::nrf52< gatt_server > server;\n\nint main()\n{\n    for ( ;; )\n        server.run();\n}\n@endcode\n\nbluetoe::nrf52<> is just a template alias that points to bluetoe::link_layer::link_layer, which takes additonal link layer configuration arguments. Again, Bluetoe applies resonable default to the link layer configuration. But if needed, parameters like buffer sizes, are configurable.\n\n@section define_gap And what's with GAP?\n\n@section Advertising\n\nGAP is an other important protocol that allows a GATT client to discover devices, connect to them and to gather basic informations about a device. In Bluetooth all possible options related to GAP are passed as options to the @ref bluetoe::server type definition.\n\nA Bluetoe GATT server will start to advertise by default and will restart to advertise after a client have disconnected to the server. Bluetoe will advertise the implemented services by default.\n\n*/"
  },
  {
    "path": "bluetoe/meta_types.hpp",
    "content": "#ifndef BLUETOE_META_TYPES_HPP\n#define BLUETOE_META_TYPES_HPP\n\nnamespace bluetoe {\n\n    namespace details {\n\n        /*\n         * A meta_type, that every option to a characteristic must have\n         */\n        struct valid_characteristic_option_meta_type {};\n\n        /*\n         * A meta_type that tags every valid option to a service\n         */\n        struct valid_service_option_meta_type {};\n\n        /*\n         * A meta_type that tags every valid option to a server\n         */\n        struct valid_server_option_meta_type {};\n\n        /*\n         * A service declaration\n         */\n        struct service_meta_type {};\n\n        /*\n         * A characteristic declaration\n         */\n        struct characteristic_meta_type {};\n\n        /*\n         * A server parameter that defines how advertising data is created\n         */\n        struct advertising_data_meta_type {};\n\n        /*\n         * A server parameter that defines how the response to a scan request is created\n         */\n        struct scan_response_data_meta_type {};\n\n        /*\n         * A option only viable for a hardware binding\n         */\n        struct binding_option_meta_type {};\n    }\n}\n\n#endif\n\n"
  },
  {
    "path": "bluetoe/mixin.hpp",
    "content": "#ifndef BLUETOE_MIXIN_HPP\n#define BLUETOE_MIXIN_HPP\n\n#include <bluetoe/meta_tools.hpp>\n\nnamespace bluetoe {\n    template < typename ... T >\n    struct mixin;\n\n    template < typename ... Options >\n    class server;\n\n    namespace details {\n        struct mixin_meta_type {};\n\n        template < typename MixinList >\n        struct sum_mixins;\n\n        template <>\n        struct sum_mixins< std::tuple<> >\n        {\n            typedef std::tuple<> type;\n        };\n\n        template < typename ... Ts, typename ... Ms >\n        struct sum_mixins< std::tuple< mixin< Ts... >, Ms... > >{\n            typedef typename add_type<\n                std::tuple< Ts... >,\n                typename sum_mixins< std::tuple< Ms... > >::type >::type type;\n        };\n\n        template < typename List, typename Element >\n        struct extract_service_mixins;\n\n        template < typename ... Ms, typename ... Options >\n        struct extract_service_mixins< std::tuple< Ms... >, bluetoe::service< Options... > >\n        {\n            typedef typename find_all_by_meta_type< mixin_meta_type, Options... >::type mixins;\n            typedef typename add_type< mixins, std::tuple< Ms... > >::type              type;\n        };\n\n        template < typename ... Ms, typename T >\n        struct extract_service_mixins< std::tuple< Ms... >, T >\n        {\n            typedef std::tuple< Ms... > type;\n        };\n\n        template < typename ... Options >\n        struct collect_mixins\n        {\n            typedef typename find_all_by_meta_type< mixin_meta_type, Options... >::type         server_mixins;\n            typedef typename fold< std::tuple< Options ... >, extract_service_mixins >::type    service_mixins;\n            typedef typename add_type< server_mixins, service_mixins >::type                mixins;\n            typedef typename sum_mixins< mixins >::type                                     type;\n        };\n\n    }\n\n    /**\n     * @brief class to be mixed into the server instance\n     *\n     * This option can be passed to a bluetoe::server or to a bluetoe::service. The bluetoe::server will derive from the given\n     * types in the given order. If the option is used multiple times, the server will first derive from the type given to the\n     * server and then from the type given to the services in the same order as the services are passed to the server.\n     *\n     * As there is no way defined to pass constructor arguments, all types have to have default constructors.\n     *\n     * @sa server\n     * @sa service\n     * @sa mixin_read_handler\n     * @sa mixin_write_handler\n     * @sa mixin_read_blob_handler\n     * @sa mixin_write_blob_handler\n     * @sa mixin_write_indication_control_point_handler\n     * @sa mixin_write_notification_control_point_handler\n     */\n    template < typename ... T >\n    struct mixin {\n        /** @cond HIDDEN_SYMBOLS */\n        struct meta_type :\n            details::mixin_meta_type,\n            details::valid_service_option_meta_type,\n            details::valid_server_option_meta_type {};\n\n        /** @endcond */\n    };\n\n\n}\n#endif\n"
  },
  {
    "path": "bluetoe/notification_queue.hpp",
    "content": "#ifndef BLUETOE_NOTIFICATION_QUEUE_HPP\n#define BLUETOE_NOTIFICATION_QUEUE_HPP\n\n#include <cstdint>\n#include <cstdlib>\n#include <utility>\n#include <cassert>\n#include <algorithm>\n#include <iterator>\n\nnamespace bluetoe {\n\n    namespace details {\n        /**\n         * @brief type of entry\n         */\n        enum class notification_queue_entry_type {\n            /** returned if there no entry */\n            empty,\n            /** returned if the entry is a notification */\n            notification,\n            /** returned if the entry is an indication */\n            indication\n        };\n\n        template < typename Size, int C >\n        class notification_queue_impl_base;\n\n        static constexpr std::size_t no_outstanding_indicaton = ~std::size_t{ 0 };\n    }\n\n    /**\n     * @brief class responsible to keep track of those characteristics that have outstanding\n     *        notifications or indications.\n     *\n     * All operations on the queue must be reentrent / atomic!\n     *\n     * @param Sizes List of number of characteristics that have notifications and / or indications enabled by priorities.\n     * @param Mixin a class to be mixed in, to allow empty base class optimizations\n     *\n     * For all function, index is an index into a list of all the characterstics with notifications / indications\n     * enable. The queue is implemented by an array that contains a few bits (2) per characteristic to store the\n     * requested (or queued) notifications / indications.\n     */\n    template < typename Sizes, class Mixin >\n    class notification_queue : public Mixin, details::notification_queue_impl_base< Sizes, 0 >\n    {\n    public:\n        /** @cond HIDDEN_SYMBOLS */\n        using entry_type = details::notification_queue_entry_type;\n        /** @endcond */\n\n        /**\n         * @brief constructs an empty notification_queue_impl\n         *\n         * All constructor arguments are ment to be passed to the derived Mixin.\n         */\n        template < class ... Args >\n        notification_queue( Args... mixin_arguments );\n\n        /**\n         * @brief queue the indexed characteristic for notification\n         *\n         * Once a characteristic is queued for notification, the function\n         * dequeue_indication_or_confirmation() will return { notification, index }\n         * on a future call.\n         *\n         * If the given characteristic was already queued for notification, the function\n         * will not have any side effects.\n         *\n         * The function returns true, if the given characteristic was not already queued for notifications.\n         *\n         * @pre index < Size\n         */\n        bool queue_notification( std::size_t index );\n\n        /**\n         * @brief queue the indexed characteristic for indication\n         *\n         * Once a characteristic is queued for indication, the function\n         * dequeue_indication_or_confirmation() will return { indication, index }\n         * om a future call.\n         *\n         * If the given characteristic was already queued for indication,\n         * the function will not have any side effects.\n         *\n         * The function returns true, if the given characteristic was not already queued for indication or\n         * if a confirmations is still awaited.\n         *\n         * @pre index < Size\n         */\n        bool queue_indication( std::size_t index );\n\n        /**\n         * @brief to be called, when a ATT Handle Value Confirmation was received.\n         *\n         * If not outstanding confirmation is registered, the\n         * function has not side effect.\n         */\n        void indication_confirmed();\n\n        /**\n         * @brief return a next notification or indication to be send.\n         *\n         * For a returned notification, the function will remove the returned entry.\n         * For a returned indication, the function will change the entry to 'unconfirmed' and\n         * will not return any indications until indication_confirmed() is called for the\n         * returned index.\n         */\n        std::pair< details::notification_queue_entry_type, std::size_t > dequeue_indication_or_confirmation();\n\n        /**\n         * @brief removes all entries from the queue\n         */\n        void clear_indications_and_confirmations();\n\n    private:\n        using impl = details::notification_queue_impl_base< Sizes, 0 >;\n        std::size_t outstanding_confirmation_index_;\n    };\n\n    // impl\n    template < typename Sizes, class Mixin >\n    template < class ... Args >\n    notification_queue< Sizes, Mixin >::notification_queue( Args... mixin_arguments )\n        : Mixin( mixin_arguments... )\n        , outstanding_confirmation_index_( details::no_outstanding_indicaton )\n    {\n    }\n\n    template < typename Sizes, class Mixin >\n    bool notification_queue< Sizes, Mixin >::queue_notification( std::size_t index )\n    {\n        return impl::queue_notification( index );\n    }\n\n    template < typename Sizes, class Mixin >\n    bool notification_queue< Sizes, Mixin >::queue_indication( std::size_t index )\n    {\n        return impl::queue_indication( index );\n    }\n\n    template < typename Sizes, class Mixin >\n    void notification_queue< Sizes, Mixin >::indication_confirmed()\n    {\n        outstanding_confirmation_index_ = details::no_outstanding_indicaton;\n    }\n\n    template < typename Sizes, class Mixin >\n    std::pair< details::notification_queue_entry_type, std::size_t > notification_queue< Sizes, Mixin >::dequeue_indication_or_confirmation()\n    {\n        const auto result = impl::dequeue_indication_or_confirmation( 0, outstanding_confirmation_index_ );\n\n        return result;\n    }\n\n    template < typename Sizes, class Mixin >\n    void notification_queue< Sizes, Mixin >::clear_indications_and_confirmations()\n    {\n        outstanding_confirmation_index_ = details::no_outstanding_indicaton;\n        impl::clear_indications_and_confirmations();\n    }\n\n    namespace details\n    {\n        // C is introduced to make baseclasses with the very same Size not ambiguous\n        template < int Size, int C >\n        class notification_queue_impl\n        {\n        public:\n            notification_queue_impl()\n            {\n                clear_indications_and_confirmations();\n            }\n\n            bool queue_notification( std::size_t index )\n            {\n                assert( index < Size );\n                return add( index, notification_bit );\n            }\n\n            bool queue_indication( std::size_t index )\n            {\n                assert( index < Size );\n\n                return add( index, indication_bit );\n            }\n\n            std::pair< notification_queue_entry_type, std::size_t > dequeue_indication_or_confirmation( std::size_t offset, std::size_t& outstanding_confirmation )\n            {\n                bool ignore_first = true;\n\n                // loop over all entries in a circle\n                for ( std::size_t i = next_; ignore_first || i != next_; i = ( i + 1 ) % Size )\n                {\n                    ignore_first = false;\n                    auto entry = at( i );\n\n                    if ( entry & indication_bit && outstanding_confirmation == no_outstanding_indicaton )\n                    {\n                        outstanding_confirmation = i + offset;\n                        next_ = ( i + 1 ) % Size;\n                        remove( i, indication_bit );\n                        return { notification_queue_entry_type::indication, i + offset };\n                    }\n                    else if ( entry & notification_bit )\n                    {\n                        next_ = ( i + 1 ) % Size;\n                        remove( i, notification_bit );\n                        return { notification_queue_entry_type::notification, i + offset };\n                    }\n\n                }\n\n                return { notification_queue_entry_type::empty, 0 };\n            }\n\n            void clear_indications_and_confirmations()\n            {\n                next_ = 0;\n                std::fill( std::begin( queue_ ), std::end( queue_ ), 0 );\n            }\n\n        private:\n            int at( std::size_t index )\n            {\n                const auto bit_offset  = ( index * bits_per_characteristc ) % 8;\n                const auto byte_offset = index * bits_per_characteristc / 8;\n                assert( byte_offset < sizeof( queue_ ) / sizeof( queue_[ 0 ] ) );\n\n                return ( queue_[ byte_offset ] >> bit_offset ) & 0x03;\n            }\n\n            bool add( std::size_t index, int bits )\n            {\n                assert( bits & ( ( 1 << bits_per_characteristc ) -1 ) );\n                const auto bit_offset  = ( index * bits_per_characteristc ) % 8;\n                const auto byte_offset = index * bits_per_characteristc / 8;\n                assert( byte_offset < sizeof( queue_ ) / sizeof( queue_[ 0 ] ) );\n\n                const bool result = ( queue_[ byte_offset ] & ( bits << bit_offset ) ) == 0;\n                queue_[ byte_offset ] |= bits << bit_offset;\n\n                return result;\n            }\n\n            void remove( std::size_t index, int bits )\n            {\n                assert( bits & ( ( 1 << bits_per_characteristc ) -1 ) );\n                const auto bit_offset  = ( index * bits_per_characteristc ) % 8;\n                const auto byte_offset = index * bits_per_characteristc / 8;\n                assert( byte_offset < sizeof( queue_ ) / sizeof( queue_[ 0 ] ) );\n\n                queue_[ byte_offset ] &= ~( bits << bit_offset );\n            }\n\n            static constexpr std::size_t bits_per_characteristc = 2;\n\n            enum char_bits {\n                notification_bit = 0x01,\n                indication_bit   = 0x02\n            };\n\n            std::size_t     next_;\n            std::uint8_t    queue_[ ( Size * bits_per_characteristc + 7 ) / 8 ];\n        };\n\n        /**\n         * @brief Specialisation for one characteritics with notification or indication enabled\n         */\n        template < int C >\n        class notification_queue_impl< 1, C >\n        {\n        public:\n            notification_queue_impl()\n                : state_( notification_queue_entry_type::empty )\n            {\n            }\n\n            bool queue_notification( std::size_t idx )\n            {\n                static_cast< void >( idx );\n                assert( idx == 0 );\n\n                const bool result = state_ == notification_queue_entry_type::empty;\n\n                if ( result )\n                    state_ = notification_queue_entry_type::notification;\n\n                return result;\n            }\n\n            bool queue_indication( std::size_t idx )\n            {\n                static_cast< void >( idx );\n                assert( idx == 0 );\n                const bool result = state_ == notification_queue_entry_type::empty;\n\n                if ( result )\n                    state_ = notification_queue_entry_type::indication;\n\n                return result;\n            }\n\n            std::pair< notification_queue_entry_type, std::size_t > dequeue_indication_or_confirmation( std::size_t offset, std::size_t& outstanding_confirmation )\n            {\n                const auto result = state_ == notification_queue_entry_type::notification || ( state_ == notification_queue_entry_type::indication && outstanding_confirmation == details::no_outstanding_indicaton )\n                    ? std::pair< notification_queue_entry_type, std::size_t >{ static_cast< notification_queue_entry_type >( state_ ), offset }\n                    : std::pair< notification_queue_entry_type, std::size_t >{ notification_queue_entry_type::empty, 0 };\n\n                if ( result.first == notification_queue_entry_type::indication )\n                    outstanding_confirmation = offset;\n\n                if ( result.first != notification_queue_entry_type::empty )\n                    state_ = notification_queue_entry_type::empty;\n\n                return result;\n            }\n\n            void clear_indications_and_confirmations()\n            {\n                state_ = notification_queue_entry_type::empty;\n            }\n        private:\n            notification_queue_entry_type state_;\n        };\n\n        template < int C >\n        class notification_queue_impl_base< std::tuple<>, C >\n        {\n        public:\n            bool queue_notification( std::size_t ) { return false; }\n            bool queue_indication( std::size_t ) { return false; }\n\n            std::pair< notification_queue_entry_type, std::size_t > dequeue_indication_or_confirmation( std::size_t, std::size_t )\n            {\n                return { notification_queue_entry_type::empty, 0 };\n            }\n\n            void clear_indications_and_confirmations() {}\n        };\n\n        template < int Size, class ...Ts, int C >\n        class notification_queue_impl_base< std::tuple< std::integral_constant< int, Size >, Ts... >, C >\n            : public notification_queue_impl_base< std::tuple< Ts... >, C + 1 >\n            , private notification_queue_impl< Size, C >\n        {\n        public:\n            using base = notification_queue_impl_base< std::tuple< Ts... >, C + 1 >;\n            using impl = notification_queue_impl< Size, C >;\n\n            bool queue_notification( std::size_t idx )\n            {\n                return idx < Size\n                    ? impl::queue_notification( idx )\n                    : base::queue_notification( idx - Size );\n            }\n\n            bool queue_indication( std::size_t idx )\n            {\n                return idx < Size\n                    ? impl::queue_indication( idx )\n                    : base::queue_indication( idx - Size );\n            }\n\n            std::pair< notification_queue_entry_type, std::size_t > dequeue_indication_or_confirmation( std::size_t offset, std::size_t& outstanding_confirmation )\n            {\n                auto result = impl::dequeue_indication_or_confirmation( offset, outstanding_confirmation );\n\n                if ( result.first != notification_queue_entry_type::empty )\n                {\n                    return result;\n                }\n\n                result = base::dequeue_indication_or_confirmation( offset + Size, outstanding_confirmation );\n\n                return result;\n            }\n\n            void clear_indications_and_confirmations()\n            {\n                impl::clear_indications_and_confirmations();\n                base::clear_indications_and_confirmations();\n            }\n        };\n\n    } // namespace details\n\n} // namespace bluetoe\n\n#endif // include guard\n"
  },
  {
    "path": "bluetoe/outgoing_priority.hpp",
    "content": "#ifndef BLUETOE_OUTGOING_PRIORITY_HPP\n#define BLUETOE_OUTGOING_PRIORITY_HPP\n\n#include <bluetoe/meta_tools.hpp>\n\nnamespace bluetoe {\n\n    namespace details {\n        struct outgoing_priority_meta_type {};\n\n        template < typename Services, typename ServiceUUID >\n        struct number_of_additional_priorities\n        {\n            template < typename Service >\n            using has_uuid = std::is_same< typename Service::uuid, ServiceUUID >;\n\n            // find the Service from the ServiceUUID in the List of Services\n            using service = typename find_if< Services, has_uuid >::type;\n            static constexpr int size = service::notification_priority::size;\n\n            // if the number of named characteristics is equal to the number of characteristics in the service,\n            // no characteristic will have default priority\n            static constexpr int size_with_default = size == service::number_of_client_configs\n                ? size\n                : size + 1;\n\n            // For a Service that doesn't contain a priority per characteristic, there is at least one\n            // addition priority, because all characteristics in the service form have a new unique priority\n            using type = std::integral_constant< int, size_with_default == 0 ? 1 : size_with_default >;\n        };\n\n        template < typename ... Us >\n        struct check_server_parameter\n        {\n            static_assert( details::count_by_meta_type< details::service_uuid_meta_type, Us... >::count == sizeof...( Us ),\n                \"Only service UUIDs are acceptable parameters to higher_outgoing_priority<> as server parameter.\" );\n\n            static constexpr bool check = true;\n        };\n\n        template < typename ... Us >\n        struct check_service_parameter\n        {\n            static_assert( details::count_by_meta_type< details::characteristic_uuid_meta_type, Us... >::count == sizeof...( Us ),\n                \"Only characteristic UUIDs are acceptable parameters to higher_outgoing_priority<> as service parameter.\" );\n\n            static constexpr bool check = true;\n        };\n\n        template < typename T, int Prio >\n        struct add_prio;\n\n        template <>\n        struct add_prio< std::tuple<>, 0 >\n        {\n            using type = std::tuple< std::integral_constant< int, 1 > >;\n        };\n\n        template < int N, typename ...Ts >\n        struct add_prio< std::tuple< std::integral_constant< int, N >, Ts... >, 0 >\n        {\n            using type = std::tuple< std::integral_constant< int, N + 1 >, Ts... >;\n        };\n\n        template < int Prio >\n        struct add_prio< std::tuple<>, Prio >\n        {\n            using type = typename add_type<\n                std::integral_constant< int, 0 >,\n                typename add_prio< std::tuple<>, Prio -1 >::type >::type;\n        };\n\n        template < int N, typename ...Ts, int Prio >\n        struct add_prio< std::tuple< std::integral_constant< int, N >, Ts... >, Prio >\n        {\n            using type = typename add_type<\n                std::integral_constant< int, N >,\n                typename add_prio< std::tuple< Ts... >, Prio -1 >::type >::type;\n        };\n\n    }\n\n    /**\n     * @brief Defines priorities of notified or indicated characteristics.\n     *\n     * In Bluetoe, when a characteristic notification or indication have to\n     * be send, the server::notify or server::indicate function can be used\n     * to queue this characteristic for beeing send out. Once the link layer\n     * finds a free spot for a notification or indication, it will determin\n     * one of the queued characteristics, reserve a buffer,\n     * fill that buffer with the value of the characteristic and send it out.\n     *\n     * higher_outgoing_priority and lower_outgoing_priority can be used\n     * define in which order queued notifications and indications are send.\n     *\n     * The higher_outgoing_priority option can be used as option to a\n     * service, to define the priority of outgoing notifications and\n     * indications based on the characteristics UUID. UUIDs are given in\n     * decreasing order of priority. Characteristics of the service that\n     * are not named in the list have a priority that is lower than the\n     * last element in the list.\n     *\n     * The higher_outgoing_priority option can also be used as option to\n     * a server, to raise the priority of all characteristics within a\n     * service. Then, all characteristics within a service, that is not\n     * named as a parameter to higher_outgoing_priority have a priority\n     * that is less than all characteristics within the last element of\n     * the list.\n     *\n     * Example:\n     * Given that we have 3 services A, B, and C which all contain 3\n     * characteristics a, b, and c. Given this pseudo GATT server:\n     * @code\n     using server = bluetoe::server<\n        bluetoe::service<\n            A,\n            bluetoe::characteristic< a, bluetoe::notify >,\n            bluetoe::characteristic< b, bluetoe::notify >,\n            bluetoe::characteristic< c, bluetoe::notify >,\n            bluetoe::higher_outgoing_priority< b >\n        >,\n        bluetoe::service<\n            B,\n            bluetoe::characteristic< a, bluetoe::notify >,\n            bluetoe::characteristic< b, bluetoe::notify >,\n            bluetoe::characteristic< c, bluetoe::notify >,\n            bluetoe::lower_outgoing_priority< a >\n        >,\n        bluetoe::service<\n            C,\n            bluetoe::characteristic< a, bluetoe::notify >,\n            bluetoe::characteristic< b, bluetoe::notify >,\n            bluetoe::characteristic< c, bluetoe::notify >,\n            bluetoe::higher_outgoing_priority< a, b >\n        >,\n        bluetoe::higher_outgoing_priority< A >\n     >;\n     * @endcode\n     *\n     * Now, the priority of each characteristic is as follows. Characteristics comming first have\n     * higher priorities. Characteristics on the same line have equal priority.\n     * @code\n     Service:  | A       | B       | C\n     ---------------------------------------\n     highest   | b       |         |\n               | a,c     |         |\n               |         |         | a\n               |         |         | b\n               |         | b, c    | c\n     lowest    |         | a       |\n     * @endcode\n     *\n     * Note, that the characteristics b and c of service B and the characteristic c of service\n     * C have the very same priority, because B and C have the same priority and the characteristics\n     * have default (unchanged) priorities.\n     *\n     * @sa lower_outgoing_priority\n     */\n    template < typename ... UUIDs >\n    struct higher_outgoing_priority {\n        /** @cond HIDDEN_SYMBOLS */\n        struct meta_type :\n            details::outgoing_priority_meta_type,\n            details::valid_service_option_meta_type,\n            details::valid_server_option_meta_type {};\n\n        template < typename Services, typename Service >\n        struct service_base_priority\n        {\n            template < typename Sum, typename ServiceUUID >\n            struct optional_sum_prio\n            {\n                using found = std::integral_constant< bool, Sum::first_type::value || std::is_same< ServiceUUID, typename Service::uuid >::value >;\n                using prio  = typename Sum::second_type;\n\n                // Only sum up the priorities that are before ServiceUUID in UUIDs...\n                using sum   = typename details::select_type< found::value,\n                    prio,\n                    typename details::number_of_additional_priorities< Services, ServiceUUID >::type >::type;\n\n                using type = details::pair< found, sum >;\n            };\n\n            // while Service::uuid is not in UUIDs... sum up the priorities of the services\n            using type = typename details::fold_left<\n                                        std::tuple< UUIDs... >,\n                                        optional_sum_prio,\n                                        details::pair< std::false_type, std::integral_constant< int, 0 > > >::type;\n\n            static constexpr int value = type::second_type::value;\n        };\n\n        template < typename Sum, typename Service >\n        struct expand_shared_priorities\n        {\n            static constexpr int sum   = Sum::value;\n\n            // is this one of the services that share the priorities?\n            static constexpr bool shared = details::index_of< typename Service::uuid, UUIDs... >::value == sizeof...( UUIDs );\n\n            static constexpr int prios = Service::notification_priority::size;\n\n            static constexpr int shared_value = prios > sum ? prios : sum;\n            static constexpr int value = shared ? shared_value : sum;\n\n            using type = std::integral_constant< int, value >;\n        };\n\n        // this function is called on the server instantiation\n        template < typename Services, typename Service, typename Characteristic >\n        struct characteristic_priority\n        {\n            static constexpr auto checked = details::check_server_parameter< UUIDs... >::check;\n\n            static constexpr int service_prio = service_base_priority< Services, Service >::value;\n\n            // there is a big difference whether a Service is within UUIDs or not. In case, a Service is not within UUIDs\n            // (Service B and C in the example above), characteristics from different services can share the same priority.\n            static constexpr bool priorized_service = details::index_of< typename Service::uuid, UUIDs... >::value != sizeof...( UUIDs );\n\n            // the maximum of introduced priorities of all services that are not within UUIDs (and thus share a range of priorities).\n            static constexpr int shared_priorities = details::fold< Services, expand_shared_priorities, std::integral_constant< int, 0 > >::type::value;\n\n            static constexpr int char_prio    = Service::notification_priority::template characteristic_position< Characteristic, priorized_service, shared_priorities >::value;\n\n            static constexpr int value = service_prio + char_prio;\n        };\n\n        template < typename Services, typename Service >\n        struct numbers_from_char\n        {\n            template < typename Numbers, typename Characteristic >\n            struct impl\n            {\n                static constexpr int prio = characteristic_priority< Services, Service, Characteristic >::value;\n                using type = typename details::add_prio< Numbers, prio >::type;\n            };\n        };\n\n        // Returns a list of numbers of priorities, starting with the number of characteristics with prio 0 (highest)\n        template < typename Services >\n        struct numbers\n        {\n            template < typename List, typename Characteristic >\n            using characteristics_with_cccd = details::select_type<\n                    Characteristic::number_of_client_configs,\n                    typename details::add_type< List, Characteristic >::type,\n                    List >;\n\n            template < typename Numbers, typename Service >\n            using numbers_from_services = details::fold<\n                typename details::fold<\n                    typename Service::characteristics,\n                    characteristics_with_cccd >::type,\n                numbers_from_char< Services, Service >::template impl,\n                Numbers >;\n\n            using type = typename details::fold< Services, numbers_from_services, std::tuple<> >::type;\n        };\n\n        static constexpr std::size_t size = sizeof...( UUIDs );\n\n        // this function is called on the service instantiation\n        template < typename Characteristic, bool WithinPriorizedService, int SharedPriorities >\n        struct characteristic_position\n        {\n            static constexpr auto checked = details::check_service_parameter< UUIDs... >::check;\n\n            static constexpr int pos = details::index_of< typename Characteristic::configured_uuid, UUIDs... >::value;\n            static constexpr int value = WithinPriorizedService\n                ? pos\n                : pos + SharedPriorities - size;\n        };\n\n        /** @endcond */\n    };\n\n    /**\n     * @brief Defines priorities of notified or indicated characteristics.\n     * @sa higher_outgoing_priority\n     * @attention currently not implemented\n     */\n    template < class ... UUIDs >\n    struct lower_outgoing_priority {\n        /** @cond HIDDEN_SYMBOLS */\n        struct meta_type :\n            details::outgoing_priority_meta_type,\n            details::valid_service_option_meta_type,\n            details::valid_server_option_meta_type {};\n        /** @endcond */\n    };\n\n    /**\n     * @example priorities_example.cpp\n     * This examples shows, how to define priorities for charactertic notifications and indications.\n     */\n\n}\n\n\n#endif\n"
  },
  {
    "path": "bluetoe/pairing_status.hpp",
    "content": "#ifndef BLUETOE_SM_PAIRING_STATUS_HPP\n#define BLUETOE_SM_PAIRING_STATUS_HPP\n\nnamespace bluetoe {\n\n    /**\n     * @brief pairing status of a given connection\n     *\n     * As enumerated as \"Local Device Pairing Status\" in table 10.2, Vol. 3; Part C; 10.3.1\n     */\n    enum class device_pairing_status {\n        no_key,\n        unauthenticated_key,\n        authenticated_key,\n        authenticated_key_with_secure_connection\n    };\n\n    /**\n     * @brief the basic security attributes of a connection\n     *\n     * @sa device_pairing_status\n     */\n    struct connection_security_attributes\n    {\n        /**\n         * @brief true, if the connection is currently encrypted\n         */\n        bool                    is_encrypted;\n\n        /**\n         * @brief method that was used to exchange the long term key that is used in the connection\n         */\n        device_pairing_status   pairing_status;\n\n        /**\n         * @brief default: not encrypted, no key\n         */\n        constexpr connection_security_attributes()\n            : is_encrypted( false )\n            , pairing_status( device_pairing_status::no_key )\n        {\n        }\n\n        /**\n         * @brief c'tor to initialize both members\n         */\n        constexpr connection_security_attributes( bool encrypted, device_pairing_status status )\n            : is_encrypted( encrypted )\n            , pairing_status( status )\n        {\n        }\n    };\n}\n#endif\n"
  },
  {
    "path": "bluetoe/peripheral_connection_interval_range.hpp",
    "content": "#ifndef BLUETOE_PERIPHERAL_CONNECTION_INTERVAL_RANGE_HPP\n#define BLUETOE_PERIPHERAL_CONNECTION_INTERVAL_RANGE_HPP\n\nnamespace bluetoe {\n    static constexpr std::uint16_t no_specific_peripheral_connection_minimum_interval = 0xFFFF;\n    static constexpr std::uint16_t no_specific_peripheral_connection_maximum_interval = 0xFFFF;\n\n    namespace details {\n        struct peripheral_connection_interval_range_meta_type {};\n\n        template <\n            std::uint16_t MinInterval,\n            std::uint16_t MaxInterval >\n        struct check_peripheral_connection_interval_range_parameters\n        {\n            static_assert( ( MinInterval >= 0x0006 && MinInterval <= 0x0C80 ) || MinInterval == no_specific_peripheral_connection_minimum_interval,\n                \"Invalid value for peripheral_connection_interval_range first template parameter (MinInterval) used!\" );\n\n            static_assert( ( MaxInterval >= 0x0006 && MaxInterval <= 0x0C80 ) || MaxInterval == no_specific_peripheral_connection_maximum_interval,\n                \"Invalid value for peripheral_connection_interval_range second template parameter (MaxInterval) used!\" );\n\n            static_assert( MinInterval <= MaxInterval || MinInterval == no_specific_peripheral_connection_minimum_interval || MaxInterval == no_specific_peripheral_connection_maximum_interval,\n                \"when defining the peripheral_connection_interval_range, the minimum shall not be greater than the maximum value!\" );\n\n            typedef void type;\n        };\n\n        struct no_peripheral_connection_interval_range\n        {\n            typedef peripheral_connection_interval_range_meta_type meta_type;\n\n            static std::uint8_t* advertising_data( std::uint8_t* begin, std::uint8_t* )\n            {\n                return begin;\n            }\n        };\n    }\n\n    /**\n     * @brief add peripheral connection interval range to advertising data\n     *\n     * Adds \\<\\<Peripheral Connection Interval Range\\>\\> AD type to the advertising data.\n     * MinInterval and MaxInterval must be within the range of 0x0006 to 0x0C80.\n     * Using no_specific_peripheral_connection_minimum_interval or no_specific_peripheral_connection_maximum_interval\n     * specifies, that the respective value is not used.\n     */\n    template <\n        std::uint16_t MinInterval = no_specific_peripheral_connection_minimum_interval,\n        std::uint16_t MaxInterval = no_specific_peripheral_connection_maximum_interval,\n        typename = typename details::check_peripheral_connection_interval_range_parameters< MinInterval, MaxInterval >::type\n    >\n    struct peripheral_connection_interval_range\n    {\n        /** @cond HIDDEN_SYMBOLS */\n        struct meta_type :\n            details::peripheral_connection_interval_range_meta_type,\n            details::valid_server_option_meta_type {};\n\n        static std::uint8_t* advertising_data( std::uint8_t* begin, std::uint8_t* end )\n        {\n            if ( end - begin >= 6 )\n            {\n                *begin = 0x05;\n                ++begin;\n                *begin = 0x12;\n                ++begin;\n\n                begin = details::write_16bit( begin, MinInterval );\n                begin = details::write_16bit( begin, MaxInterval );\n            }\n\n            return begin;\n        }\n\n        /** @endcond */\n    };\n}\n\n#endif\n"
  },
  {
    "path": "bluetoe/scattered_access.hpp",
    "content": "#ifndef BLUETOE_SCATTERED_ACCESS_HPP\n#define BLUETOE_SCATTERED_ACCESS_HPP\n\n#include <bluetoe/attribute.hpp>\n#include <algorithm>\n\nnamespace bluetoe {\nnamespace details {\n\n    template < int Size >\n    std::uint8_t* copy( int offset, const std::uint8_t (&source)[ Size ], std::uint8_t* begin, std::uint8_t* end )\n    {\n        offset = std::max( 0, offset );\n        const int source_size = std::max( 0, Size - offset );\n        const int copy_size   = std::min( source_size, std::max< int >( 0, end - begin ) );\n\n        std::copy( std::begin( source ) + offset, std::begin( source ) + offset + copy_size, begin );\n\n        return begin + copy_size;\n    }\n\n    template < int a_size, int b_size, int c_size >\n    void scattered_read_access(\n        int offset,\n        const std::uint8_t (&a)[ a_size ], const std::uint8_t (&b)[ b_size ], const std::uint8_t (&c)[ c_size ],\n        std::uint8_t* out_buffer, int out_buffer_size )\n    {\n        std::uint8_t* const end = out_buffer + out_buffer_size;\n        std::uint8_t*       out = out_buffer;\n\n        out = copy( offset,                   a, out, end );\n        out = copy( offset - a_size,          b, out, end );\n              copy( offset - a_size - b_size, c, out, end );\n    }\n}\n}\n#endif\n"
  },
  {
    "path": "bluetoe/sensor_location.hpp",
    "content": "#ifndef BLUETOE_SENSOR_LOCATION_HPP\n#define BLUETOE_SENSOR_LOCATION_HPP\n\nnamespace bluetoe {\n\n    namespace details {\n        struct sensor_location_meta_type {};\n    }\n\n    /**\n     * @brief type to keep a bluetoe::location value\n     */\n    template < std::uint8_t L >\n    struct sensor_location_tag\n    {\n        /** @cond HIDDEN_SYMBOLS */\n        struct meta_type :\n            details::sensor_location_meta_type,\n            details::valid_service_option_meta_type {};\n\n        static constexpr std::uint8_t                 value = L;\n        /** @endcond */\n    };\n\n    /**\n     * @brief enumeration of sensor_location (org.bluetooth.characteristic.sensor_location)\n     *\n     * The class contains a lot of alias-declarations for known, assigned sensor locations.\n     */\n    struct sensor_location\n    {\n        /// Other\n        using other                 = sensor_location_tag< 0 >;\n        /// Top of shoe\n        using top_of_shoe           = sensor_location_tag< 1 >;\n        /// In shoe\n        using in_shoe               = sensor_location_tag< 2 >;\n        /// Hip\n        using hip                   = sensor_location_tag< 3 >;\n        /// Front Wheel\n        using front_wheel           = sensor_location_tag< 4 >;\n        /// Left Crank\n        using left_crank            = sensor_location_tag< 5 >;\n        /// Right Crank\n        using right_crank           = sensor_location_tag< 6 >;\n        /// Left Pedal\n        using left_pedal            = sensor_location_tag< 7 >;\n        /// Right Pedal\n        using right_pedal           = sensor_location_tag< 8 >;\n        /// Front Hub\n        using front_hub             = sensor_location_tag< 9 >;\n        /// Rear Dropout\n        using rear_dropout          = sensor_location_tag< 10 >;\n        /// Chainstay\n        using chainstay             = sensor_location_tag< 11 >;\n        /// Rear Wheel\n        using rear_wheel            = sensor_location_tag< 12 >;\n        /// Rear Hub\n        using rear_hub              = sensor_location_tag< 13 >;\n        /// Chest\n        using chest                 = sensor_location_tag< 14 >;\n    };\n}\n\n#endif\n"
  },
  {
    "path": "bluetoe/server.hpp",
    "content": "#ifndef BLUETOE_SERVER_HPP\n#define BLUETOE_SERVER_HPP\n\n#include <bluetoe/codes.hpp>\n#include <bluetoe/service.hpp>\n#include <bluetoe/bits.hpp>\n#include <bluetoe/filter.hpp>\n#include <bluetoe/gatt_options.hpp>\n#include <bluetoe/server_name.hpp>\n#include <bluetoe/adv_service_list.hpp>\n#include <bluetoe/peripheral_connection_interval_range.hpp>\n#include <bluetoe/server_meta_type.hpp>\n#include <bluetoe/client_characteristic_configuration.hpp>\n#include <bluetoe/write_queue.hpp>\n#include <bluetoe/gap_service.hpp>\n#include <bluetoe/appearance.hpp>\n#include <bluetoe/mixin.hpp>\n#include <bluetoe/find_notification_data.hpp>\n#include <bluetoe/outgoing_priority.hpp>\n#include <bluetoe/link_state.hpp>\n#include <bluetoe/attribute_handle.hpp>\n#include <bluetoe/l2cap_channels.hpp>\n#include <bluetoe/notification_queue.hpp>\n#include <bluetoe/custom_advertising.hpp>\n\n#include <cstdint>\n#include <cstddef>\n#include <algorithm>\n#include <iterator>\n#include <cassert>\n\nnamespace bluetoe {\n    namespace details {\n\n        template < typename ... Options >\n        using selected_advertising_data_source =\n            typename details::find_by_meta_type<\n                        details::advertising_data_meta_type,\n                        Options...,\n                        auto_advertising_data\n                    >::type;\n\n        template < typename ... Options >\n        using selected_scan_response_data_source =\n            typename details::find_by_meta_type<\n                        details::scan_response_data_meta_type,\n                        Options...,\n                        auto_scan_response_data\n                    >::type;\n    }\n\n    /**\n     * @brief Root of the declaration of a GATT server.\n     *\n     * The server serves one or more services configured by the given Options. To configure the server, pass one or more bluetoe::service types as parameters.\n     *\n     * example:\n     * @code\n    unsigned temperature_value = 0;\n\n    typedef bluetoe::server<\n        bluetoe::service<\n            bluetoe::service_uuid< 0x8C8B4094, 0x0DE2, 0x499F, 0xA28A, 0x4EED5BC73CA9 >,\n            bluetoe::characteristic<\n                bluetoe::bind_characteristic_value< decltype( temperature_value ), &temperature_value >,\n                bluetoe::no_write_access\n            >\n        >\n    > small_temperature_service;\n     * @endcode\n     * @sa service\n     * @sa shared_write_queue\n     * @sa extend_server\n     * @sa server_name\n     * @sa appearance\n     * @sa requires_encryption\n     * @sa max_mtu_size\n     */\n    template < typename ... Options >\n    class server\n        : private details::write_queue< typename details::find_by_meta_type< details::write_queue_meta_type, Options... >::type >\n        , public details::derive_from< typename details::collect_mixins< Options... >::type >\n        , public details::selected_advertising_data_source< Options ... >\n        , public details::selected_scan_response_data_source< Options ... >\n    {\n    public:\n        /** @cond HIDDEN_SYMBOLS */\n        using services_without_gap = typename details::find_all_by_meta_type< details::service_meta_type, Options... >::type;\n        using selected_advertising_data_t = details::selected_advertising_data_source< Options ... >;\n        using selected_scan_response_data_t = details::selected_scan_response_data_source< Options ... >;\n\n        // append gap serivce for gatt servers\n        using gap_service_definition = typename details::find_by_meta_type< details::gap_service_definition_meta_type,\n            Options..., gap_service_for_gatt_servers >::type;\n        using services = typename gap_service_definition::template add_service< services_without_gap, Options... >::type;\n\n        static constexpr std::size_t number_of_client_configs = details::sum_by< services, details::sum_by_client_configs >::value;\n\n        using write_queue_type = typename details::find_by_meta_type< details::write_queue_meta_type, Options... >::type;\n\n        using notification_priority = typename details::find_by_meta_type< details::outgoing_priority_meta_type, Options..., higher_outgoing_priority<> >::type;\n\n        static_assert( std::tuple_size< typename details::find_all_by_meta_type< details::outgoing_priority_meta_type, Options... >::type >::value <= 1,\n            \"Only one of bluetoe::higher_outgoing_priority<> or bluetoe::lower_outgoing_priority<> per server allowed!\" );\n\n        using cccd_indices = typename details::find_notification_data_in_list< notification_priority, services >::cccd_indices;\n\n        using server_t       = server< Options... >;\n        using handle_mapping = details::handle_index_mapping< server_t >;\n\n        /** @endcond */\n\n        /**\n         * @brief per connection data\n         *\n         * The underlying layer have to provide the memory for a connection and pass the connection_data to l2cap_input().\n         * The purpose of this class is to store all connection related data that must be keept per connection and must\n         * be reset with a new connection.\n         */\n        class connection_data\n            : public details::client_characteristic_configurations< number_of_client_configs >\n        {\n        public:\n            connection_data()\n                : client_mtu_( details::default_att_mtu_size )\n            {\n            }\n\n            /**\n             * @brief returns the negotiated MTU\n             */\n            std::uint16_t negotiated_mtu() const\n            {\n                return std::min( server_mtu(), client_mtu_ );\n            }\n\n            /**\n             * @brief sets the MTU size of the connected client.\n             *\n             * The default is 23. Usually this function will be called by the server implementation as reaction\n             * of an \"Exchange MTU Request\".\n             * @post client_mtu() == mtu\n             */\n            void client_mtu( std::uint16_t mtu )\n            {\n                assert( mtu >= details::default_att_mtu_size );\n                client_mtu_ = mtu;\n            }\n\n            /**\n             * @brief returns the client MTU\n             *\n             * By default this returns 23 unless the client MTU was changed by call to client_mtu( std::size_t )\n             */\n            std::uint16_t client_mtu() const\n            {\n                return client_mtu_;\n            }\n\n            /**\n             * @brief returns the MTU of this server as provided in the c'tor\n             * @pre connection_data(X).server_mtu() == X\n             */\n            std::uint16_t server_mtu() const\n            {\n                return maximum_channel_mtu_size;\n            }\n\n\n        private:\n            std::uint16_t               client_mtu_;\n        };\n\n        /**\n         * @brief a server takes no runtime construction parameters\n         */\n        server();\n\n        /**\n         * @brief notifies all connected clients about this value\n         *\n         * There is no check whether there was actual a change to the value or not. It's safe to call this function from a different\n         * thread or from an interrupt service routine. But there is a check whether or not clients enabled notifications.\n         *\n         * The characteristic<> must have been given the notify parameter.\n         *\n         * @sa notify\n         * @sa characteristic\n         *\n         * Example:\n         @code\n        std::int32_t temperature;\n\n        typedef bluetoe::server<\n            bluetoe::service_uuid< 0x8C8B4094, 0x0DE2, 0x499F, 0xA28A, 0x4EED5BC73CA9 >,\n            bluetoe::characteristic<\n                bluetoe::bind_characteristic_value< decltype( temperature ), &temperature >,\n                bluetoe::notify\n            >\n        > temperature_service;\n\n        int main()\n        {\n            temperature_service server;\n\n            server.notify( temperature );\n        }\n        @endcode\n\n         * @return The function will return false, if the given notification was ignored, because the\n         *         characteristic is already queued for notification, but not yet send out.\n         */\n        template < class T >\n        bool notify( const T& value );\n\n        /**\n         * Notify a characteristic, by giving the characteristic UUID.\n         *\n         * The charactieristic to be notify, must have been configured for notificaton.\n         * If multiple characteristics exists with the given UUID, the first characteristic will be notified.\n         *\n         * @sa notify\n         * @sa characteristic\n         *\n         * Example:\n         @code\n        std::int32_t temperature;\n\n        typedef bluetoe::server<\n            bluetoe::service_uuid< 0x8C8B4094, 0x0DE2, 0x499F, 0xA28A, 0x4EED5BC73CA9 >,\n            bluetoe::characteristic<\n                bluetoe::characteristic_uuid16< 0x0815 >,\n                bluetoe::bind_characteristic_value< decltype( temperature ), &temperature >,\n                bluetoe::notify\n            >\n        > temperature_service;\n\n        int main()\n        {\n            temperature_service server;\n\n            server.notify< bluetoe::characteristic_uuid16< 0x0815 > >();\n        }\n        @endcode\n\n         * @return The function will return false, if the given notification was ignored, because the\n         *         characteristic is already queued for notification, but not yet send out.\n         */\n        template < class CharacteristicUUID >\n        bool notify();\n\n        /**\n         * @brief sends indications to all connceted clients.\n         *\n         * The function is mostly similar to notify(). Instead of an ATT notification, an ATT indication is send.\n         *\n         * @return The function will return false, if the given indication was ignored, because the\n         *         characteristic is already queued for indication, but not yet send out or the confirmation\n         *         to a previous send out indication of this characteristic was not received yet.\n         */\n        template < class T >\n        bool indicate( const T& value );\n\n        /**\n         * @brief sends indications to all connceted clients.\n         *\n         * The function is mostly similar to notify(). Instead of an ATT notification, an ATT indication is send.\n         *\n         * @return The function will return false, if the given indication was ignored, because the\n         *         characteristic is already queued for indication, but not yet send out or the confirmation\n         *         to a previous send out indication of this characteristic was not received yet.\n         */\n        template < class CharacteristicUUID >\n        bool indicate();\n\n        /**\n         * @brief returns true, if the given connection is configured to send indications for the given characteristic\n         */\n        template < class CharacteristicUUID >\n        bool configured_for_indications( const details::client_characteristic_configuration& ) const;\n\n        /**\n         * @brief returns true, if the given connection is configured to send notifications for the given characteristic\n         */\n        template < class CharacteristicUUID >\n        bool configured_for_notifications( const details::client_characteristic_configuration& ) const;\n\n        /**\n         * @brief returns true, if the given connection is configured to send indications or notifications for the given characteristic\n         */\n        template < class CharacteristicUUID >\n        bool configured_for_notifications_or_indications( const details::client_characteristic_configuration& ) const;\n\n        /** @cond HIDDEN_SYMBOLS */\n        // function relevant only for l2cap layers\n        /**\n         * @brief function to be called by a L2CAP implementation to provide the input from the L2CAP layer and the data assiziate with the connection\n         */\n        template < typename ConnectionData >\n        void l2cap_input( const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size, ConnectionData& );\n\n        template < typename ConnectionData >\n        void l2cap_output( std::uint8_t*, std::size_t& out_size, ConnectionData& );\n\n        /**\n         * @brief returns the advertising data to the L2CAP implementation\n         */\n        std::size_t advertising_data( std::uint8_t* buffer, std::size_t buffer_size ) const;\n\n\n        /**\n         * @brief returns the scan response data to the L2CAP implementation\n         */\n        std::size_t scan_response_data( std::uint8_t* buffer, std::size_t buffer_size ) const;\n\n        /**\n         * @brief returns true, if there is a chance that advertising data has been changed\n         */\n        bool advertising_or_scan_response_data_has_been_changed();\n\n        typedef bool (*lcap_notification_callback_t)( const details::notification_data& item, void* usr_arg, details::notification_type type );\n\n        /**\n         * @brief sets the callback for the l2cap layer to receive notifications and indications\n         *\n         * The server will inform the l2cap layer about that fact, that there are outstanding notifications for all connection for the\n         * characteristic given by the item pointer. It's up to the l2cap layer to call notification_output.\n         * The usr_arg is stored and passed to the given callback, when the callback is called.\n         */\n        void notification_callback( lcap_notification_callback_t, void* usr_arg );\n\n        /**\n         * @attention this function must be called with every client that got disconnected.\n         */\n        template < typename Connection >\n        void client_disconnected( Connection& );\n\n        typedef details::server_meta_type meta_type;\n\n        static details::attribute attribute_at( std::size_t index );\n\n        static constexpr std::uint16_t channel_id               = l2cap_channel_ids::att;\n        static constexpr std::size_t   minimum_channel_mtu_size = bluetoe::details::default_att_mtu_size;\n        static constexpr std::size_t   maximum_channel_mtu_size = bluetoe::details::find_by_meta_type<\n                details::mtu_size_meta_type,\n                Options...,\n                max_mtu_size< bluetoe::details::default_att_mtu_size >\n            >::type::mtu;\n\n        template < class PreviousData = details::no_such_type >\n        class channel_data_t\n            : public notification_queue<\n                typename notification_priority::template numbers< services >::type,\n                PreviousData >\n            , public connection_data\n        {\n        };\n\n        void notification_subscription_changed( const details::client_characteristic_configuration& );\n        /** @endcond */\n\n    private:\n        static constexpr std::size_t number_of_attributes       = details::sum_by< services, details::sum_by_attributes >::value;\n\n        static_assert( std::tuple_size< services >::value > 0, \"A server should at least contain one service.\" );\n\n        void error_response( std::uint8_t opcode, details::att_error_codes error_code, std::uint16_t handle, std::uint8_t* output, std::size_t& out_size );\n        void error_response( std::uint8_t opcode, details::att_error_codes error_code, std::uint8_t* output, std::size_t& out_size );\n\n        static details::att_error_codes access_result_to_att_code( details::attribute_access_result, details::att_error_codes default_att_code );\n\n        /**\n         * for a PDU what starts with an opcode, followed by a pair of handles, the function checks the size of the PDU (must be A or B) and checks the handles.\n         * The starting handle must not be 0, must be greate than ending_handle and must be with in the range of attributes available.\n         * If the function returns true, everything is fine and starting_handle and ending_handle are filled correctly. Otherwise, an error response was generated.\n         */\n        template < std::size_t A, std::size_t B = A >\n        bool check_size_and_handle_range( const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size, std::uint16_t& starting_handle, std::uint16_t& ending_handle );\n\n        template < std::size_t A, std::size_t B = A >\n        bool check_size_and_handle( const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size, std::uint16_t& handle, std::size_t& index );\n        bool check_handle( const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size, std::uint16_t& handle, std::size_t& index );\n\n        template < typename ConnectionData >\n        void handle_exchange_mtu_request( const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size, ConnectionData& );\n        void handle_find_information_request( const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size );\n        void handle_find_by_type_value_request( const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size );\n        template < typename ConnectionData >\n        void handle_read_by_type_request( const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size, ConnectionData& );\n        template < typename ConnectionData >\n        void handle_read_request( const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size, ConnectionData& );\n        template < typename ConnectionData >\n        void handle_read_blob_request( const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size, ConnectionData& );\n        void handle_read_by_group_type_request( const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size );\n        template < typename ConnectionData >\n        void handle_read_multiple_request( const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size, ConnectionData& );\n        template < typename ConnectionData >\n        void handle_write_request( const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size, ConnectionData& );\n        template < typename ConnectionData >\n        void handle_write_command( const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size, ConnectionData& );\n\n        template < typename Connection >\n        void handle_prepair_write_request( const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size, Connection&, const details::no_such_type& );\n        template < typename Connection, typename WriteQueue >\n        void handle_prepair_write_request( const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size, Connection&, const WriteQueue& );\n        template < typename Connection >\n        void handle_execute_write_request( const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size, Connection&, const details::no_such_type& );\n        template < typename Connection, typename WriteQueue >\n        void handle_execute_write_request( const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size, Connection&, const WriteQueue& );\n        void handle_value_confirmation( const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size, connection_data& );\n\n        template < class Iterator, class Filter = details::all_uuid_filter >\n        void all_attributes( std::uint16_t starting_handle, std::uint16_t ending_handle, Iterator&, const Filter& filter = details::all_uuid_filter() );\n\n        template < class Iterator, class Filter = details::all_uuid_filter >\n        bool all_services_by_group( std::uint16_t starting_handle, std::uint16_t ending_handle, Iterator&, const Filter& filter = details::all_uuid_filter() );\n\n        std::uint8_t* collect_handle_uuid_tuples( std::size_t start, std::size_t end, bool only_16_bit, std::uint8_t* output, std::uint8_t* output_end );\n\n        static void write_128bit_uuid( std::uint8_t* out, const details::attribute& char_declaration );\n\n        // mapping of a last handle to a valid attribute index\n        std::size_t last_handle_index( std::uint16_t ending_handle );\n\n        std::size_t advertising_data_impl( std::uint8_t* buffer, std::size_t buffer_size, const auto_advertising_data& ) const;\n\n        template < class T >\n        std::size_t advertising_data_impl( std::uint8_t* buffer, std::size_t buffer_size, const T& ) const;\n\n        std::size_t scan_response_data_impl( std::uint8_t* buffer, std::size_t buffer_size, const auto_scan_response_data& ) const;\n\n        template < class T >\n        std::size_t scan_response_data_impl( std::uint8_t* buffer, std::size_t buffer_size, const T& ) const;\n\n        // data\n        lcap_notification_callback_t l2cap_cb_;\n        void*                        l2cap_arg_;\n\n        static_assert(\n            std::is_same<\n                typename details::find_by_not_meta_type<\n                    details::valid_server_option_meta_type,\n                    Options...\n                >::type, details::no_such_type\n            >::value, \"Option passed to a server that is not a valid server option.\" );\n    protected: // for testing\n        /** @cond HIDDEN_SYMBOLS */\n\n        details::notification_data find_notification_data( const void* ) const;\n        details::notification_data find_notification_data_by_index( std::size_t client_characteristic_configuration_index ) const;\n\n        /** @endcond */\n    };\n\n    /**\n     * @example server_example.cpp\n     * This is a very small sample showing, how to define a very small GATT server.\n     */\n\n    /**\n     * @brief adds additional options to a given server definition\n     *\n     * example:\n     * @code\n    unsigned temperature_value = 0;\n\n    typedef bluetoe::server<\n    ...\n    > small_temperature_server;\n\n    typedef bluetoe::extend_server<\n        small_temperature_server,\n        bluetoe::server_name< name >\n    > small_named_temperature_service;\n\n     * @endcode\n     * @sa server\n     */\n    template < typename Server, typename ... Options >\n    struct extend_server;\n\n    template < typename ... ServerOptions, typename ... Options >\n    struct extend_server< server< ServerOptions... >, Options... > : server< ServerOptions..., Options... >\n    {\n    };\n\n    /*\n     * Implementation\n     */\n    /** @cond HIDDEN_SYMBOLS */\n    template < typename ... Options >\n    server< Options... >::server()\n        : l2cap_cb_( nullptr )\n    {\n\n    }\n\n    template < typename ... Options >\n    template < typename ConnectionData >\n    void server< Options... >::l2cap_input( const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size, ConnectionData& connection )\n    {\n        // clip the output size to the negotiated mtu\n        out_size = std::min< std::size_t >( out_size, connection.negotiated_mtu() );\n\n        assert( in_size != 0 );\n        assert( out_size >= details::default_att_mtu_size );\n\n        const details::att_opcodes opcode = static_cast< details::att_opcodes >( input[ 0 ] );\n\n        switch ( opcode )\n        {\n        // do not respond to an error response:\n        case details::att_opcodes::error_response:\n            out_size = 0;\n            break;\n\n        case details::att_opcodes::exchange_mtu_request:\n            handle_exchange_mtu_request( input, in_size, output, out_size, connection );\n            break;\n        case details::att_opcodes::find_information_request:\n            handle_find_information_request( input, in_size, output, out_size );\n            break;\n        case details::att_opcodes::find_by_type_value_request:\n            handle_find_by_type_value_request( input, in_size, output, out_size );\n            break;\n        case details::att_opcodes::read_by_type_request:\n            handle_read_by_type_request( input, in_size, output, out_size, connection );\n            break;\n        case details::att_opcodes::read_request:\n            handle_read_request( input, in_size, output, out_size, connection );\n            break;\n        case details::att_opcodes::read_blob_request:\n            handle_read_blob_request( input, in_size, output, out_size, connection );\n            break;\n        case details::att_opcodes::read_by_group_type_request:\n            handle_read_by_group_type_request( input, in_size, output, out_size );\n            break;\n        case details::att_opcodes::read_multiple_request:\n            handle_read_multiple_request( input, in_size, output, out_size, connection );\n            break;\n        case details::att_opcodes::write_request:\n            handle_write_request( input, in_size, output, out_size, connection );\n            break;\n        case details::att_opcodes::write_command:\n            handle_write_command( input, in_size, output, out_size, connection );\n            break;\n        case details::att_opcodes::prepare_write_request:\n            handle_prepair_write_request( input, in_size, output, out_size, connection, write_queue_type() );\n            break;\n        case details::att_opcodes::execute_write_request:\n            handle_execute_write_request( input, in_size, output, out_size, connection, write_queue_type() );\n            break;\n        case details::att_opcodes::confirmation:\n            handle_value_confirmation( input, in_size, output, out_size, connection );\n            break;\n        default:\n            error_response( *input, details::att_error_codes::request_not_supported, output, out_size );\n            break;\n        }\n    }\n\n    template < typename ... Options >\n    template < typename ConnectionData >\n    void server< Options... >::l2cap_output( std::uint8_t* output, std::size_t& out_size, ConnectionData& connection )\n    {\n        const auto pending = connection.dequeue_indication_or_confirmation();\n\n        if ( pending.first != details::notification_queue_entry_type::empty )\n        {\n            const std::uint16_t required_flag = pending.first == details::notification_queue_entry_type::notification\n                ? details::client_characteristic_configuration_notification_enabled\n                : details::client_characteristic_configuration_indication_enabled;\n\n            const auto data = find_notification_data_by_index( pending.second );\n\n            if ( connection.client_configurations().flags( data.client_characteristic_configuration_index() ) & required_flag &&\n                 out_size >= 3 )\n            {\n                auto read = details::attribute_access_arguments::read( output + 3, output + out_size, 0, connection.client_configurations(), connection.security_attributes(), this );\n                auto attr = attribute_at( data.attribute_table_index() );\n                auto rc   = attr.access( read, data.attribute_table_index() );\n\n                if ( rc == details::attribute_access_result::success )\n                {\n                    *output = pending.first == details::notification_queue_entry_type::notification\n                        ? bits( details::att_opcodes::notification )\n                        : bits( details::att_opcodes::indication );\n                    details::write_handle( output +1, handle_mapping::handle_by_index( data.attribute_table_index() ) );\n\n                    out_size = 3 + read.buffer_size;\n                    return;\n                }\n            }\n        }\n\n        out_size = 0;\n    }\n\n    namespace details {\n        // all this hassel to stop gcc from complaining about constant argument to if\n        template < bool >\n        struct copy_name\n        {\n            static std::uint8_t* impl( std::uint8_t* begin, std::uint8_t* end, const char* const name )\n            {\n                if ( ( end - begin ) <= 2 )\n                    return begin;\n\n                const std::size_t name_length  = std::strlen( name );\n                const std::size_t max_name_len = std::min< std::size_t >( name_length, end - begin - 2 );\n\n                if ( name_length > 0 )\n                {\n                    begin[ 0 ] = max_name_len + 1;\n                    begin[ 1 ] = max_name_len == name_length\n                        ? bits( details::gap_types::complete_local_name )\n                        : bits( details::gap_types::shortened_local_name );\n\n                    std::copy( name + 0, name + max_name_len, &begin[ 2 ] );\n                    begin += max_name_len + 2;\n                }\n\n                return begin;\n            }\n        };\n\n        template <>\n        struct copy_name< false >\n        {\n            static std::uint8_t* impl( std::uint8_t* begin, std::uint8_t*, const char* const )\n            {\n                return begin;\n            }\n        };\n\n    }\n\n    template < typename ... Options >\n    std::size_t server< Options... >::advertising_data( std::uint8_t* begin, std::size_t buffer_size ) const\n    {\n        return advertising_data_impl( begin, buffer_size, selected_advertising_data_t() );\n    }\n\n    template < typename ... Options >\n    template < class Advertiser >\n    std::size_t server< Options... >::advertising_data_impl( std::uint8_t* begin, std::size_t buffer_size, const Advertiser& ) const\n    {\n        return static_cast< const Advertiser& >( *this ).advertising_data( begin, buffer_size );\n    }\n\n    template < typename ... Options >\n    std::size_t server< Options... >::advertising_data_impl( std::uint8_t* begin, std::size_t buffer_size, const auto_advertising_data& ) const\n    {\n        std::uint8_t* const end = begin + buffer_size;\n\n        if ( buffer_size >= 3 )\n        {\n            begin[ 0 ] = 2;\n            begin[ 1 ] = bits( details::gap_types::flags );\n            // LE General Discoverable Mode | BR/EDR Not Supported\n            begin[ 2 ] = 6;\n\n            begin += 3;\n        }\n\n        using device_appearance = typename details::find_by_meta_type<\n                details::device_appearance_meta_type,\n                Options...,\n                appearance::unknown\n            >::type;\n\n        using appearance_advertising_config = typename details::find_by_meta_type<\n            details::advertise_appearance_meta_type,\n            Options...,\n            no_advertise_appearance >::type;\n\n        begin = appearance_advertising_config::template advertising_data< device_appearance >( begin, end );\n\n        typedef typename details::find_by_meta_type< details::server_name_meta_type, Options..., server_name< nullptr > >::type name;\n\n        begin = details::copy_name< name::name != nullptr >::impl( begin, end, name::name );\n\n        typedef typename details::find_by_meta_type<\n            details::list_of_16_bit_service_uuids_tag,\n            Options...,\n            details::default_list_of_16_bit_service_uuids< services >\n        >::type service_list_uuid16;\n\n        begin = service_list_uuid16::advertising_data( begin, end );\n\n        typedef typename details::find_by_meta_type<\n            details::list_of_128_bit_service_uuids_tag,\n            Options...,\n            details::default_list_of_128_bit_service_uuids< services >\n        >::type service_list_uuid128;\n\n        begin = service_list_uuid128::advertising_data( begin, end );\n\n        typedef typename details::find_by_meta_type<\n            details::peripheral_connection_interval_range_meta_type,\n            Options...,\n            details::no_peripheral_connection_interval_range\n        >::type peripheral_connection_interval_range_ad;\n\n        begin = peripheral_connection_interval_range_ad::advertising_data( begin, end );\n\n        // add aditional empty AD to be visible to Nordic sniffer\n        if ( static_cast< unsigned >( end - begin ) >= 2u )\n        {\n            *begin = 0;\n            ++begin;\n            *begin = 0;\n            ++begin;\n        }\n\n        return buffer_size - ( end - begin );\n    }\n\n    template < typename ... Options >\n    std::size_t server< Options... >::scan_response_data( std::uint8_t* buffer, std::size_t buffer_size ) const\n    {\n        return scan_response_data_impl( buffer, buffer_size, selected_scan_response_data_t() );\n    }\n\n    template < typename ... Options >\n    std::size_t server< Options... >::scan_response_data_impl( std::uint8_t* buffer, std::size_t /* buffer_size */, const auto_scan_response_data& ) const\n    {\n        // add aditional empty AD to be visible to Nordic sniffer.\n        // Some stacks do not recognize the response without this empty AD.\n        buffer[ 0 ] = 0;\n        buffer[ 1 ] = 0;\n\n        return 2;\n    }\n\n    template < typename ... Options >\n    template < class T >\n    std::size_t server< Options... >::scan_response_data_impl( std::uint8_t* buffer, std::size_t buffer_size, const T& ) const\n    {\n        return static_cast< const T& >( *this ).scan_response_data( buffer, buffer_size );\n    }\n\n    template < typename ... Options >\n    bool server< Options... >::advertising_or_scan_response_data_has_been_changed()\n    {\n        const bool advertising_changed   = this->advertising_data_dirty();\n        const bool scan_response_changed = this->scan_response_data_dirty();\n\n        return advertising_changed || scan_response_changed;\n    }\n\n    template < typename ... Options >\n    template < class T >\n    bool server< Options... >::notify( const T& value )\n    {\n        static_assert( number_of_client_configs != 0, \"there is no characteristic that is configured for notification or indication\" );\n\n        const details::notification_data data = find_notification_data( &value );\n        assert( data.valid() );\n\n        if ( l2cap_cb_ )\n            return l2cap_cb_( data, l2cap_arg_, details::notification_type::notification );\n\n        return false;\n    }\n\n    template < typename ... Options >\n    template < class CharacteristicUUID >\n    bool server< Options... >::notify()\n    {\n        static_assert( number_of_client_configs != 0, \"there is no characteristic that is configured for notification or indication\" );\n\n        using characteristic = typename details::find_characteristic_data_by_uuid_in_service_list< services, CharacteristicUUID >::type;\n\n        static_assert( !std::is_same< characteristic, details::no_such_type >::value, \"Notified characteristic not found by UUID.\" );\n        static_assert( characteristic::has_notification, \"Characteristic must be configured for notification!\" );\n\n        const auto data = details::find_notification_by_uuid< notification_priority, services, typename characteristic::characteristic_t >::data();\n\n        if ( l2cap_cb_ )\n            return l2cap_cb_( data, l2cap_arg_, details::notification_type::notification );\n\n        return false;\n    }\n\n    template < typename ... Options >\n    template < class T >\n    bool server< Options... >::indicate( const T& value )\n    {\n        static_assert( number_of_client_configs != 0, \"there is no characteristic that is configured for notification or indication\" );\n\n        const details::notification_data data = find_notification_data( &value );\n        assert( data.valid() );\n\n        if ( l2cap_cb_ )\n            return l2cap_cb_( data, l2cap_arg_, details::notification_type::indication );\n\n        return false;\n    }\n\n    template < typename ... Options >\n    template < class CharacteristicUUID >\n    bool server< Options... >::indicate()\n    {\n        static_assert( number_of_client_configs != 0, \"there is no characteristic that is configured for notification or indication\" );\n\n        using characteristic = typename details::find_characteristic_data_by_uuid_in_service_list< services, CharacteristicUUID >::type;\n\n        static_assert( !std::is_same< characteristic, details::no_such_type >::value, \"Indicated characteristic not found by UUID.\" );\n        static_assert( characteristic::has_indication, \"Characteristic must be configured for indication!\" );\n\n        const auto data = details::find_notification_by_uuid< notification_priority, services, typename characteristic::characteristic_t >::data();\n\n        if ( l2cap_cb_ )\n            return l2cap_cb_( data, l2cap_arg_, details::notification_type::indication );\n\n        return false;\n    }\n\n    template < typename ... Options >\n    template < class CharacteristicUUID >\n    bool server< Options... >::configured_for_indications( const details::client_characteristic_configuration& connection ) const\n    {\n        using characteristic = typename details::find_characteristic_data_by_uuid_in_service_list< services, CharacteristicUUID >::type;\n        const auto data = details::find_notification_by_uuid< notification_priority, services, typename characteristic::characteristic_t >::data();\n\n        return connection.flags( data.client_characteristic_configuration_index() ) & details::client_characteristic_configuration_indication_enabled;\n    }\n\n    template < typename ... Options >\n    template < class CharacteristicUUID >\n    bool server< Options... >::configured_for_notifications( const details::client_characteristic_configuration& connection ) const\n    {\n        using characteristic = typename details::find_characteristic_data_by_uuid_in_service_list< services, CharacteristicUUID >::type;\n        const auto data = details::find_notification_by_uuid< notification_priority, services, typename characteristic::characteristic_t >::data();\n\n        return connection.flags( data.client_characteristic_configuration_index() ) & details::client_characteristic_configuration_notification_enabled;\n    }\n\n    template < typename ... Options >\n    template < class CharacteristicUUID >\n    bool server< Options... >::configured_for_notifications_or_indications( const details::client_characteristic_configuration& connection ) const\n    {\n        using characteristic = typename details::find_characteristic_data_by_uuid_in_service_list< services, CharacteristicUUID >::type;\n        const auto data = details::find_notification_by_uuid< notification_priority, services, typename characteristic::characteristic_t >::data();\n\n        static const auto both = ( details::client_characteristic_configuration_notification_enabled | details::client_characteristic_configuration_indication_enabled );\n\n        return connection.flags( data.client_characteristic_configuration_index() ) & both;\n    }\n\n    template < typename ... Options >\n    void server< Options... >::notification_callback( lcap_notification_callback_t cb, void* usr_arg )\n    {\n        l2cap_cb_  = cb;\n        l2cap_arg_ = usr_arg;\n    }\n\n    template < typename ... Options >\n    template < typename Connection >\n    void server< Options... >::client_disconnected( Connection& client )\n    {\n        this->free_write_queue( client );\n    }\n\n    template < typename ... Options >\n    details::attribute server< Options... >::attribute_at( std::size_t index )\n    {\n        return details::attribute_from_service_list< services, server< Options... >, cccd_indices >::attribute_at( index );\n    }\n\n    template < typename ... Options >\n    void server< Options... >::error_response( std::uint8_t opcode, details::att_error_codes error_code, std::uint16_t handle, std::uint8_t* output, std::size_t& out_size )\n    {\n        if ( out_size >= 5 )\n        {\n            output[ 0 ] = bits( details::att_opcodes::error_response );\n            output[ 1 ] = opcode;\n            output[ 2 ] = handle & 0xff;\n            output[ 3 ] = handle >> 8;\n            output[ 4 ] = bits( error_code );\n            out_size = 5;\n        }\n        else\n        {\n            out_size = 0 ;\n        }\n    }\n\n    template < typename ... Options >\n    void server< Options... >::error_response( std::uint8_t opcode, details::att_error_codes error_code, std::uint8_t* output, std::size_t& out_size )\n    {\n        error_response( opcode, error_code, 0, output, out_size );\n    }\n\n\n    template < typename ... Options >\n    details::att_error_codes server< Options... >::access_result_to_att_code( details::attribute_access_result access_code, details::att_error_codes default_att_code )\n    {\n        // if it can be copied lossles into a att_error_codes, it is a att_error_codes\n        const details::att_error_codes result = static_cast< details::att_error_codes >( access_code );\n\n        return static_cast< details::attribute_access_result >( result ) == access_code\n            ? result\n            : default_att_code;\n    }\n\n    template < typename ... Options >\n    template < std::size_t A, std::size_t B >\n    bool server< Options... >::check_size_and_handle_range(\n        const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size, std::uint16_t& starting_handle, std::uint16_t& ending_handle )\n    {\n        if ( in_size != A && in_size != B )\n        {\n            error_response( *input, details::att_error_codes::invalid_pdu, output, out_size );\n            return false;\n        }\n\n        starting_handle = details::read_handle( &input[ 1 ] );\n        ending_handle   = details::read_handle( &input[ 3 ] );\n\n        if ( starting_handle == 0 || starting_handle > ending_handle )\n        {\n            error_response( *input, details::att_error_codes::invalid_handle, starting_handle, output, out_size );\n            return false;\n        }\n\n        if ( handle_mapping::first_index_by_handle( starting_handle ) == details::invalid_attribute_index )\n        {\n            error_response( *input, details::att_error_codes::attribute_not_found, starting_handle, output, out_size );\n            return false;\n        }\n\n        return true;\n    }\n\n    template < typename ... Options >\n    template < std::size_t A, std::size_t B >\n    bool server< Options... >::check_size_and_handle( const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size, std::uint16_t& handle, std::size_t& index )\n    {\n        if ( in_size != A && in_size != B )\n        {\n            error_response( *input, details::att_error_codes::invalid_pdu, output, out_size );\n            return false;\n        }\n\n        return check_handle( input, in_size, output, out_size, handle, index );\n    }\n\n    template < typename ... Options >\n    bool server< Options... >::check_handle( const std::uint8_t* input, std::size_t, std::uint8_t* output, std::size_t& out_size, std::uint16_t& handle, std::size_t& index )\n    {\n        handle = details::read_handle( &input[ 1 ] );\n\n        if ( handle == 0 )\n        {\n            error_response( *input, details::att_error_codes::invalid_handle, handle, output, out_size );\n            return false;\n        }\n\n        index = handle_mapping::index_by_handle( handle );\n\n        if ( index == details::invalid_attribute_index )\n        {\n            error_response( *input, details::att_error_codes::invalid_handle, handle, output, out_size );\n            return false;\n        }\n\n        return true;\n    }\n\n    template < typename ... Options >\n    template < typename ConnectionData >\n    void server< Options... >::handle_exchange_mtu_request( const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size, ConnectionData& connection )\n    {\n        if ( in_size != 3 )\n            return error_response( *input, details::att_error_codes::invalid_pdu, output, out_size );\n\n        const std::uint16_t mtu = details::read_16bit( input + 1 );\n\n        if ( mtu < details::default_att_mtu_size )\n            return error_response( *input, details::att_error_codes::invalid_pdu, output, out_size );\n\n        connection.client_mtu( mtu );\n\n        *output = bits( details::att_opcodes::exchange_mtu_response );\n        details::write_16bit( output + 1, connection.server_mtu() );\n\n        out_size = 3u;\n    }\n\n    template < typename ... Options >\n    void server< Options... >::handle_find_information_request( const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size )\n    {\n        std::uint16_t starting_handle, ending_handle;\n\n        if ( !check_size_and_handle_range< 5u >( input, in_size, output, out_size, starting_handle, ending_handle ) )\n            return;\n\n        const std::size_t start_index = handle_mapping::first_index_by_handle( starting_handle );\n        const bool only_16_bit_uuids = attribute_at( start_index ).uuid != bits( details::gatt_uuids::internal_128bit_uuid );\n\n        std::size_t ending_index = handle_mapping::first_index_by_handle( ending_handle );\n\n        // if the ending handle points not on an existing attribute, the search will end at the next, lower handle\n        if ( ending_index != details::invalid_attribute_index && handle_mapping::handle_by_index( ending_index ) != ending_handle )\n            --ending_index;\n\n        std::uint8_t*        write_ptr = &output[ 0 ];\n        std::uint8_t* const  write_end = write_ptr + out_size;\n\n        *write_ptr = bits( details::att_opcodes::find_information_response );\n        ++write_ptr;\n\n        if ( write_ptr != write_end )\n        {\n            *write_ptr = bits(\n                only_16_bit_uuids\n                    ? details::att_uuid_format::short_16bit\n                    : details::att_uuid_format::long_128bit );\n\n            ++write_ptr;\n\n        }\n\n        write_ptr = collect_handle_uuid_tuples( start_index, ending_index, only_16_bit_uuids, write_ptr, write_end );\n\n        out_size = write_ptr - &output[ 0 ];\n    }\n\n    namespace details {\n        template < class Server >\n        struct value_filter\n        {\n            value_filter( const std::uint8_t* begin, const std::uint8_t* end, Server& s )\n                : begin_( begin )\n                , end_( end )\n                , server_( s )\n            {\n            }\n\n            bool operator()( std::uint16_t, const details::attribute& attr ) const\n            {\n                auto read = details::attribute_access_arguments::compare_value( begin_, end_, &server_ );\n                return attr.access( read, 1 ) == details::attribute_access_result::value_equal;\n            }\n\n            const std::uint8_t* const begin_;\n            const std::uint8_t* const end_;\n            Server&                   server_;\n        };\n\n        struct collect_find_by_type_groups\n        {\n            collect_find_by_type_groups( std::uint8_t* begin, std::uint8_t* end )\n                : begin_( begin )\n                , end_( end )\n                , current_( begin )\n            {\n            }\n\n            template < typename Service >\n            bool operator()( std::uint16_t start_handle, std::uint16_t end_handle, const details::attribute& )\n            {\n                if ( end_ -  current_ >= 4 )\n                {\n                    current_ = details::write_handle( current_, start_handle );\n                    current_ = details::write_handle( current_, end_handle );\n\n                    return true;\n                }\n\n                return false;\n            }\n\n            std::uint8_t size() const\n            {\n                return current_ - begin_;\n            }\n\n            std::uint8_t* const begin_;\n            std::uint8_t* const end_;\n            std::uint8_t*       current_;\n        };\n    }\n\n    template < typename ... Options >\n    void server< Options... >::handle_find_by_type_value_request( const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size )\n    {\n        std::uint16_t starting_handle, ending_handle;\n\n        if ( !check_size_and_handle_range< 9u, 23u >( input, in_size, output, out_size, starting_handle, ending_handle ) )\n            return;\n\n        // the spec (v4.2) doesn't define, what to return in this case, but this seems to be a resonable response\n        if ( details::read_handle( &input[ 5 ] ) != bits( details::gatt_uuids::primary_service ) )\n            return error_response( *input, details::att_error_codes::unsupported_group_type, starting_handle, output, out_size );\n\n        details::collect_find_by_type_groups iterator( output + 1 , output + out_size );\n\n        if ( all_services_by_group( starting_handle, ending_handle, iterator, details::value_filter< server< Options... > >( &input[ 7 ], &input[ in_size ], *this ) ) )\n        {\n            *output  = bits( details::att_opcodes::find_by_type_value_response );\n            out_size = iterator.size() + 1;\n        }\n        else\n        {\n            error_response( *input, details::att_error_codes::attribute_not_found, starting_handle, output, out_size );\n        }\n\n    }\n\n    template < typename ... Options >\n    template < typename ConnectionData >\n    void server< Options... >::handle_read_request( const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size, ConnectionData& connection )\n    {\n        std::uint16_t handle;\n        std::size_t   index;\n\n        if ( !check_size_and_handle< 3 >( input, in_size, output, out_size, handle, index ) )\n            return;\n\n        auto read = details::attribute_access_arguments::read( output + 1, output + out_size, 0, connection.client_configurations(), connection.security_attributes(), this );\n        auto rc   = attribute_at( index ).access( read, index );\n\n        if ( rc == details::attribute_access_result::success )\n        {\n            *output  = bits( details::att_opcodes::read_response );\n            out_size = 1 + read.buffer_size;\n        }\n        else\n        {\n            error_response( *input, access_result_to_att_code( rc, details::att_error_codes::read_not_permitted ), handle, output, out_size );\n        }\n    }\n\n    template < typename ... Options >\n    template < typename ConnectionData >\n    void server< Options... >::handle_read_blob_request( const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size, ConnectionData& connection )\n    {\n        std::uint16_t handle;\n        std::size_t   index;\n\n        if ( !check_size_and_handle< 5 >( input, in_size, output, out_size, handle, index ) )\n            return;\n\n        const std::uint16_t offset = details::read_16bit( input + 3 );\n\n        auto read = details::attribute_access_arguments::read( output + 1, output + out_size, offset, connection.client_configurations(), connection.security_attributes(), this );\n        auto rc   = attribute_at( index ).access( read, index );\n\n        if ( rc == details::attribute_access_result::success )\n        {\n            *output  = bits( details::att_opcodes::read_blob_response );\n            out_size = 1 + read.buffer_size;\n        }\n        else\n        {\n            error_response( *input, access_result_to_att_code( rc, details::att_error_codes::read_not_permitted ), handle, output, out_size );\n        }\n     }\n\n    namespace details {\n        template < typename Server >\n        struct collect_attributes\n        {\n            void operator()( std::size_t index, const details::attribute& attr )\n            {\n                static constexpr std::size_t maximum_pdu_size = 253u;\n                static constexpr std::size_t header_size      = 2u;\n\n                if ( end_ - current_ >= static_cast< std::ptrdiff_t >( header_size ) )\n                {\n                    const std::size_t max_data_size = std::min< std::size_t >( end_ - current_, maximum_pdu_size + header_size ) - header_size;\n\n                    auto read = attribute_access_arguments::read( current_ + header_size, current_ + header_size + max_data_size, 0, config_, security_, &server_ );\n                    auto rc   = attr.access( read, index );\n\n                    if ( rc == details::attribute_access_result::success )\n                    {\n                        assert( read.buffer_size <= maximum_pdu_size );\n\n                        if ( first_ )\n                        {\n                            size_   = read.buffer_size + header_size;\n                            first_  = false;\n                        }\n\n                        if ( read.buffer_size + header_size == size_ )\n                        {\n                            current_ = details::write_handle( current_, handle_index_mapping< Server >::handle_by_index( index ) );\n                            current_ += static_cast< std::uint8_t >( read.buffer_size );\n                        }\n                    }\n                }\n            }\n\n            collect_attributes( std::uint8_t* begin, std::uint8_t* end,\n                const details::client_characteristic_configuration& config,\n                const connection_security_attributes& security,\n                Server& server )\n                : begin_( begin )\n                , current_( begin )\n                , end_( end )\n                , size_( 0 )\n                , first_( true )\n                , config_( config )\n                , security_( security )\n                , server_( server )\n            {\n            }\n\n            std::uint8_t size() const\n            {\n                return current_ - begin_;\n            }\n\n            std::uint8_t data_size() const\n            {\n                return size_;\n            }\n\n            bool empty() const\n            {\n                return current_ == begin_;\n            }\n\n            std::uint8_t*   begin_;\n            std::uint8_t*   current_;\n            std::uint8_t*   end_;\n            std::uint8_t    size_;\n            bool            first_;\n            details::client_characteristic_configuration config_;\n            connection_security_attributes security_;\n            Server&         server_;\n        };\n    }\n\n    template < typename ... Options >\n    template < typename ConnectionData >\n    void server< Options... >::handle_read_by_type_request( const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size, ConnectionData& connection )\n    {\n        std::uint16_t starting_handle, ending_handle;\n\n        if ( !check_size_and_handle_range< 5 + 2, 5 + 16 >( input, in_size, output, out_size, starting_handle, ending_handle ) )\n             return;\n\n        details::collect_attributes< server< Options... > > iterator( output + 2, output + out_size,\n            connection.client_configurations(), connection.security_attributes(), *this );\n\n        all_attributes( starting_handle, ending_handle, iterator, details::uuid_filter( input + 5, in_size == 5 + 16 ) );\n\n        if ( !iterator.empty() )\n        {\n            output[ 0 ] = bits( details::att_opcodes::read_by_type_response );\n            output[ 1 ] = iterator.data_size();\n            out_size = 2 + iterator.size();\n        }\n        else\n        {\n            error_response( *input, details::att_error_codes::attribute_not_found, starting_handle, output, out_size );\n        }\n    }\n\n    namespace details {\n        template < typename CCCDIndices, typename ServiceList, typename Server >\n        struct collect_primary_services\n        {\n            collect_primary_services( std::uint8_t*& output, std::uint8_t* end, std::uint16_t starting_index, std::uint16_t starting_handle, std::uint16_t ending_handle, std::uint8_t& attribute_data_size, Server& server )\n                : output_( output )\n                , end_( end )\n                , index_( details::handle_index_mapping< Server >::first_index_by_handle( starting_index ) )\n                , starting_index_( details::handle_index_mapping< Server >::first_index_by_handle( starting_handle ) )\n                , ending_index_( ending_handle )\n                , stoped_( false )\n                , first_( true )\n                , is_128bit_uuid_( true )\n                , attribute_data_size_( attribute_data_size )\n                , server_( server )\n            {\n            }\n\n            template< typename Service >\n            void each()\n            {\n                if ( !stoped_\n                    && ( starting_index_ != details::invalid_attribute_index && starting_index_ <= index_ )\n                    && ( index_ <= ending_index_ || ending_index_ == details::invalid_attribute_index ) )\n                {\n                    if ( first_ )\n                    {\n                        is_128bit_uuid_         = Service::uuid::is_128bit;\n                        first_                  = false;\n                        attribute_data_size_    = is_128bit_uuid_ ? 16 + 4 : 2 + 4;\n                    }\n                    // stop reading once, there is a service with a different UUID size, which would cause a gap\n                    else if ( is_128bit_uuid_ != Service::uuid::is_128bit )\n                    {\n                        stoped_ = true;\n                    }\n\n                    /// TODO: ClientCharacteristicIndex is derivable from Service and ServiceList, if 0 is used,\n                    /// some templates are most likely more than once instanciated\n                    output_ = Service::template read_primary_service_response< CCCDIndices, 0, ServiceList, Server >( output_, end_, index_, is_128bit_uuid_, server_ );\n                }\n\n                index_ += Service::number_of_attributes;\n            }\n\n                  std::uint8_t*&  output_;\n                  std::uint8_t*   end_;\n                  std::size_t     index_;\n            const std::size_t     starting_index_;\n            const std::size_t     ending_index_;\n                  bool            stoped_;\n                  bool            first_;\n                  bool            is_128bit_uuid_;\n                  std::uint8_t&   attribute_data_size_;\n                  Server&         server_;\n        };\n    }\n\n    template < typename ... Options >\n    void server< Options... >::handle_read_by_group_type_request( const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size )\n    {\n        std::uint16_t starting_handle, ending_handle;\n\n        if ( !check_size_and_handle_range< 5 + 2, 5 + 16 >( input, in_size, output, out_size, starting_handle, ending_handle ) )\n            return;\n\n        if ( in_size == 5 + 16 || details::read_handle( &input[ 5 ] ) != bits( details::gatt_uuids::primary_service ) )\n            return error_response( *input, details::att_error_codes::unsupported_group_type, starting_handle, output, out_size );\n\n        std::uint8_t*       begin = output;\n        std::uint8_t* const end   = output + out_size;\n\n        begin = details::write_opcode( begin, details::att_opcodes::read_by_group_type_response );\n        ++begin; // room in the output for the size\n\n        std::uint8_t* const data_begin = begin;\n        details::for_< services >::each( details::collect_primary_services< cccd_indices, services, server< Options... > >( begin, end, 1, starting_handle, ending_handle, *(begin -1 ), *this ) );\n\n        if ( begin == data_begin )\n        {\n            error_response( *input, details::att_error_codes::attribute_not_found, starting_handle, output, out_size );\n        }\n        else\n        {\n            out_size = begin - output;\n        }\n    }\n\n    template < typename ... Options >\n    template < typename ConnectionData >\n    void server< Options... >::handle_read_multiple_request( const std::uint8_t* input, std::size_t in_size, std::uint8_t* const output, std::size_t& out_size, ConnectionData& cc )\n    {\n        if ( in_size < 5 || in_size % 2 == 0 )\n            return error_response( *input, details::att_error_codes::invalid_pdu, output, out_size );\n\n        const std::uint8_t opcode = *input;\n        ++input;\n        --in_size;\n\n        std::uint8_t* const end_output = output + out_size;\n        std::uint8_t*       out_ptr    = output;\n\n        *out_ptr = bits( details::att_opcodes::read_multiple_response );\n        ++out_ptr;\n\n        for ( const std::uint8_t* const end_input = input + in_size; input != end_input; input += 2 )\n        {\n            const std::uint16_t handle = details::read_handle( input );\n\n            if ( handle == 0 )\n                return error_response( opcode, details::att_error_codes::invalid_handle, handle, output, out_size );\n\n            const std::size_t index = handle_mapping::index_by_handle( handle );\n            if ( index == details::invalid_attribute_index )\n                return error_response( opcode, details::att_error_codes::invalid_handle, handle, output, out_size );\n\n            auto read = details::attribute_access_arguments::read( out_ptr, end_output, 0, cc.client_configurations(), cc.security_attributes(), this );\n            auto rc   = attribute_at( index ).access( read, index );\n\n            if ( rc == details::attribute_access_result::success )\n            {\n                out_ptr += read.buffer_size;\n                assert( out_ptr <= end_output );\n            }\n            else\n            {\n                return error_response( opcode, access_result_to_att_code( rc, details::att_error_codes::read_not_permitted ), handle, output, out_size );\n            }\n        }\n\n        out_size = out_ptr - output;\n    }\n\n    template < typename ... Options >\n    template < typename ConnectionData >\n    void server< Options... >::handle_write_request( const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size, ConnectionData& connection )\n    {\n        if ( in_size < 3 )\n            return error_response( *input, details::att_error_codes::invalid_pdu, output, out_size );\n\n        std::uint16_t handle;\n        std::size_t   index;\n\n        if ( !check_handle( input, in_size, output, out_size, handle, index ) )\n            return;\n\n        auto write = details::attribute_access_arguments::write( input + 3, input + in_size, 0, connection.client_configurations(), connection.security_attributes(), this );\n        auto rc    = attribute_at( index ).access( write, index );\n\n        if ( rc == details::attribute_access_result::success )\n        {\n            *output  = bits( details::att_opcodes::write_response );\n            out_size = 1;\n        }\n        else\n        {\n            error_response( *input, access_result_to_att_code( rc, details::att_error_codes::write_not_permitted ), handle, output, out_size );\n        }\n    }\n\n    template < typename ... Options >\n    template < typename ConnectionData >\n    void server< Options... >::handle_write_command( const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size, ConnectionData& cc )\n    {\n        // just like a write request\n        handle_write_request( input, in_size, output, out_size, cc );\n\n        // but ignore all output\n        out_size = 0;\n    }\n\n    template < typename ... Options >\n    template < typename Connection >\n    void server< Options... >::handle_prepair_write_request( const std::uint8_t* input, std::size_t, std::uint8_t* output, std::size_t& out_size, Connection&, const details::no_such_type& )\n    {\n        error_response( *input, details::att_error_codes::request_not_supported, output, out_size );\n    }\n\n    template < typename ... Options >\n    template < typename Connection, typename WriteQueue >\n    void server< Options... >::handle_prepair_write_request( const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size, Connection& client, const WriteQueue& )\n    {\n        if ( in_size < 5 )\n            return error_response( *input, details::att_error_codes::invalid_pdu, output, out_size );\n\n        std::uint16_t handle;\n        std::size_t   index;\n\n        if ( !check_handle( input, in_size, output, out_size, handle, index ) )\n            return;\n\n        auto write = details::attribute_access_arguments::check_write( this );\n        auto rc    = attribute_at( index ).access( write, index );\n\n        if ( rc != details::attribute_access_result::success )\n            return error_response( *input, access_result_to_att_code( rc, details::att_error_codes::write_not_permitted ), handle, output, out_size );\n\n        // find size in the queue to write all but the opcode\n        std::uint8_t* const queue_element = this->allocate_from_write_queue( in_size - 1, client );\n\n        if ( queue_element == nullptr )\n            return error_response( *input, details::att_error_codes::prepare_queue_full, handle, output, out_size );\n\n        std::copy( input + 1, input + in_size, queue_element );\n\n        *output = bits( details::att_opcodes::prepare_write_response );\n\n        out_size = std::min< std::size_t >( out_size, in_size );\n        std::copy( input + 1, input + out_size, output + 1 );\n    }\n\n    template < typename ... Options >\n    template < typename Connection >\n    void server< Options... >::handle_execute_write_request( const std::uint8_t* input, std::size_t, std::uint8_t* output, std::size_t& out_size, Connection&, const details::no_such_type& )\n    {\n        error_response( *input, details::att_error_codes::request_not_supported, output, out_size );\n    }\n\n    template < typename ... Options >\n    template < typename Connection, typename WriteQueue >\n    void server< Options... >::handle_execute_write_request( const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size, Connection& client, const WriteQueue& )\n    {\n        if ( in_size != 2 || ( input[ 1 ] != 0 && input[ 1 ] != 1 ) )\n            return error_response( *input, details::att_error_codes::invalid_pdu, output, out_size );\n\n        // the write queue will be freed in any case\n        details::write_queue_guard< connection_data, details::write_queue< write_queue_type > > queue_guard( client, *this );\n\n        const std::uint8_t execute_flag = input[ 1 ];\n\n        if ( execute_flag )\n        {\n            for ( std::pair< std::uint8_t*, std::size_t > queue = this->first_write_queue_element( client ); queue.first; queue = this->next_write_queue_element( queue.first, client ) )\n            {\n                const std::uint16_t handle = details::read_handle( queue.first );\n                const std::uint16_t offset = details::read_16bit( queue.first + 2 );\n\n                const std::size_t attribute_index = handle_mapping::index_by_handle( handle );\n\n                auto write = details::attribute_access_arguments::write( queue.first + 4 , queue.first + queue.second,\n                                offset, client.client_configurations(), client.security_attributes(), this );\n                auto rc    = attribute_at( attribute_index ).access( write, attribute_index );\n\n                if ( rc != details::attribute_access_result::success )\n                {\n                    this->free_write_queue( client );\n\n                    if ( rc == details::attribute_access_result::invalid_attribute_value_length )\n                        return error_response( *input, details::att_error_codes::invalid_attribute_value_length, handle, output, out_size );\n\n                    return error_response( *input, details::att_error_codes::invalid_offset, handle, output, out_size );\n                }\n            }\n        }\n\n        this->free_write_queue( client );\n\n        *output  = bits( details::att_opcodes::execute_write_response );\n        out_size = 1;\n    }\n\n    template < typename ... Options >\n    void server< Options... >::handle_value_confirmation( const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size, connection_data& )\n    {\n        if ( in_size != 1 )\n            return error_response( *input, static_cast< details::att_error_codes >( 0x04 ), output, out_size );\n\n        out_size = 0;\n\n        if ( l2cap_cb_ )\n            l2cap_cb_( details::notification_data(), l2cap_arg_, details::notification_type::confirmation );\n    }\n\n\n    template < typename ... Options >\n    template < class Iterator, class Filter >\n    void server< Options... >::all_attributes( std::uint16_t starting_handle, std::uint16_t ending_handle, Iterator& iter, const Filter& filter )\n    {\n        const std::size_t last_index = last_handle_index( ending_handle );\n\n        for ( std::size_t index = handle_mapping::first_index_by_handle( starting_handle ); index <= last_index; ++index )\n        {\n            const details::attribute attr = attribute_at( index );\n\n            if ( filter( index, attr ) )\n                iter( index, attr );\n        }\n    }\n\n    namespace details {\n        template < class Iterator, class Filter, class AllServices, class Server >\n        struct services_by_group\n        {\n            services_by_group( std::uint16_t starting_handle, std::uint16_t ending_handle, Iterator& iterator, const Filter& filter, bool& found )\n                : starting_index_( details::handle_index_mapping< Server >::first_index_by_handle( starting_handle ) )\n                , ending_index_( details::handle_index_mapping< Server >::first_index_by_handle( ending_handle ) )\n                , index_( 0 )\n                , iterator_( iterator )\n                , filter_( filter )\n                , found_( found )\n            {\n                // if the ending_handle does not point to a specific handle, the last attribute befor that is ment.\n                if ( ending_index_ != details::invalid_attribute_index && details::handle_index_mapping< Server >::handle_by_index( ending_index_ ) != ending_handle )\n                {\n                    --ending_index_;\n                }\n            }\n\n            template< typename Service >\n            void each()\n            {\n                if ( ( starting_index_ != details::invalid_attribute_index && starting_index_ <= index_ )\n                    && ( index_ <= ending_index_ || ending_index_ == details::invalid_attribute_index ) )\n                {\n                    const details::attribute& attr = Server::attribute_at( index_ );\n\n                    using mapping = details::handle_index_mapping< Server >;\n\n                    if ( filter_( index_, attr ) )\n                    {\n                        found_ = iterator_.template operator()< Service >(\n                            mapping::handle_by_index( index_ ),\n                            mapping::handle_by_index( index_ + Service::number_of_attributes - 1 ),\n                            attr ) || found_;\n                    }\n                }\n\n                index_ += Service::number_of_attributes;\n            }\n\n            std::size_t     starting_index_;\n            std::size_t     ending_index_;\n            std::size_t     index_;\n            Iterator&       iterator_;\n            const Filter&   filter_;\n            bool&           found_;\n        };\n    }\n\n    template < typename ... Options >\n    template < class Iterator, class Filter >\n    bool server< Options... >::all_services_by_group( std::uint16_t starting_handle, std::uint16_t ending_handle, Iterator& iterator, const Filter& filter )\n    {\n        bool result = false;\n        details::services_by_group< Iterator, Filter, services, server< Options...  > > service_iterator( starting_handle, ending_handle, iterator, filter, result );\n        details::for_< services >::each( service_iterator );\n\n        return result;\n    }\n\n    template < typename ... Options >\n    std::uint8_t* server< Options... >::collect_handle_uuid_tuples( std::size_t start, std::size_t end, bool only_16_bit, std::uint8_t* out, std::uint8_t* out_end )\n    {\n        const std::size_t size_per_tuple = only_16_bit\n            ? 2 + 2\n            : 2 + 16;\n\n        for ( ; ( start <= end || end == details::invalid_attribute_index ) && start < number_of_attributes\n            && static_cast< std::size_t >( out_end - out ) >= size_per_tuple; ++start )\n        {\n            const details::attribute attr = attribute_at( start );\n            const bool is_16_bit_uuids    = attr.uuid != bits( details::gatt_uuids::internal_128bit_uuid );\n\n            if ( only_16_bit == is_16_bit_uuids )\n            {\n                details::write_handle( out, handle_mapping::handle_by_index( start ) );\n\n                if ( is_16_bit_uuids )\n                {\n                    details::write_16bit_uuid( out + 2, attr.uuid );\n                }\n                else\n                {\n                    write_128bit_uuid( out + 2, attribute_at( start - 1 ) );\n                }\n\n                out += size_per_tuple;\n            }\n        }\n\n        return out;\n    }\n\n    template < typename ... Options >\n    void server< Options... >::write_128bit_uuid( std::uint8_t* out, const details::attribute& char_declaration )\n    {\n        // this is a little bit tricky: To save memory, details::attribute contains only 16 bit uuids at all,\n        // but the \"Characteristic Value Declaration\" contain 16 bit uuids. However, as the \"Characteristic Value Declaration\"\n        // \"is the first Attribute after the characteristic declaration\", the attribute just in front of the\n        // \"Characteristic Value Declaration\" contains the the 128 bit uuid.\n        assert( char_declaration.uuid == bits( details::gatt_uuids::characteristic ) );\n\n        std::uint8_t buffer[ 3 + 16 ];\n        auto read = details::attribute_access_arguments::read( buffer, 0 );\n        char_declaration.access( read, 1 );\n\n        assert( read.buffer_size == sizeof( buffer ) );\n\n        std::copy( &read.buffer[ 3 ], &read.buffer[ 3 + 16 ], out );\n    }\n\n    template < typename ... Options >\n    std::size_t server< Options... >::last_handle_index( std::uint16_t ending_handle )\n    {\n        const std::size_t mapped = handle_mapping::first_index_by_handle( ending_handle );\n\n        return mapped == details::invalid_attribute_index\n            ? number_of_attributes - 1\n            : mapped;\n    }\n\n    template < typename ... Options >\n    details::notification_data server< Options... >::find_notification_data( const void* value ) const\n    {\n        return details::find_notification_data_in_list< notification_priority, services >::find_notification_data( value );\n    }\n\n    template < typename ... Options >\n    details::notification_data server< Options... >::find_notification_data_by_index( std::size_t client_characteristic_configuration_index ) const\n    {\n        return details::find_notification_data_in_list< notification_priority, services >::find_notification_data_by_index( client_characteristic_configuration_index );\n    }\n\n    template < typename ... Options >\n    void server< Options... >::notification_subscription_changed( const details::client_characteristic_configuration& data )\n    {\n        using cb_t = typename details::find_by_meta_type<\n            details::cccd_callback_meta_type,\n            Options...,\n            no_client_characteristic_configuration_update_callback >::type;\n\n        cb_t::client_characteristic_configuration_updated( *this, data );\n    }\n\n    /** @endcond */\n}\n\n#endif\n"
  },
  {
    "path": "bluetoe/server_meta_type.hpp",
    "content": "#ifndef BLUETOE_SERVER_META_TYPE_HPP\n#define BLUETOE_SERVER_META_TYPE_HPP\n\nnamespace bluetoe {\n    namespace details {\n        struct server_meta_type {};\n    }\n}\n\n#endif\n"
  },
  {
    "path": "bluetoe/server_name.hpp",
    "content": "#ifndef BLUETOE_SERVER_NAME_HPP\n#define BLUETOE_SERVER_NAME_HPP\n\n#include <bluetoe/meta_types.hpp>\n\nnamespace bluetoe {\n\n    namespace details {\n        struct server_name_meta_type {};\n    }\n\n    /**\n     * @brief adds a discoverable device name\n     */\n    template < const char* const Name >\n    struct server_name {\n        /** @cond HIDDEN_SYMBOLS */\n        struct meta_type :\n            details::server_name_meta_type,\n            details::valid_server_option_meta_type {};\n\n        static constexpr char const* name = Name;\n\n        static constexpr const char* value()\n        {\n            return name;\n        }\n\n        static constexpr std::size_t size()\n        {\n            return std::strlen( name );\n        }\n        /** @endcond */\n    };\n\n}\n\n#endif\n"
  },
  {
    "path": "bluetoe/service.hpp",
    "content": "#ifndef BLUETOE_SERVICE_HPP\n#define BLUETOE_SERVICE_HPP\n\n#include <bluetoe/service_uuid.hpp>\n#include <bluetoe/attribute.hpp>\n#include <bluetoe/codes.hpp>\n#include <bluetoe/meta_tools.hpp>\n#include <bluetoe/meta_types.hpp>\n#include <bluetoe/uuid.hpp>\n#include <bluetoe/characteristic.hpp>\n#include <bluetoe/bits.hpp>\n#include <bluetoe/find_notification_data.hpp>\n#include <bluetoe/outgoing_priority.hpp>\n#include <cstddef>\n#include <cassert>\n#include <algorithm>\n#include <type_traits>\n\nnamespace bluetoe {\n\n    template < const char* const >\n    struct service_name {\n        /** @cond HIDDEN_SYMBOLS */\n        using meta_type = details::valid_service_option_meta_type;\n        /** @endcond */\n    };\n\n    namespace details {\n        struct is_secondary_service_meta_type {};\n        struct include_service_meta_type {};\n        struct service_defintion_tag {};\n\n        template < typename ... Options >\n        struct count_service_attributes;\n    }\n\n    /**\n     * @brief a 128-Bit UUID used to identify a service.\n     *\n     * The class takes 5 parameters to store the UUID in the usual form like this:\n     * @code{.cpp}\n     * bluetoe::service_uuid< 0xF0426E52, 0x4450, 0x4F3B, 0xB058, 0x5BAB1191D92A >\n     * @endcode\n     *\n     * @sa service\n     */\n    template <\n        std::uint32_t A,\n        std::uint16_t B,\n        std::uint16_t C,\n        std::uint16_t D,\n        std::uint64_t E >\n    class service_uuid\n        /** @cond HIDDEN_SYMBOLS */\n            : public details::uuid< A, B, C, D, E >\n        /** @endcond */\n    {\n    public:\n        /** @cond HIDDEN_SYMBOLS */\n        struct meta_type :\n            details::service_uuid_128_meta_type,\n            details::valid_service_option_meta_type {};\n        /** @endcond */\n    };\n\n    /**\n     * @brief a 16-Bit UUID used to identify a service\n     *\n     * @code{.cpp}\n     * bluetoe::service_uuid16< 0x1816 >\n     * @endcode\n     *\n     * @sa service\n     */\n    template < std::uint64_t UUID >\n    class service_uuid16\n        /** @cond HIDDEN_SYMBOLS */\n            : public details::uuid16< UUID >\n        /** @endcond */\n    {\n    public:\n        /** @cond HIDDEN_SYMBOLS */\n        struct meta_type :\n            details::service_uuid_16_meta_type,\n            details::valid_service_option_meta_type {};\n        /** @endcond */\n    };\n\n    /**\n     * @brief value of the first attribute handle used in a service or characteristic\n     *\n     * @sa service\n     */\n    template < std::uint16_t Handle >\n    class start_handle\n    {\n    public:\n        /** @cond HIDDEN_SYMBOLS */\n        struct meta_type :\n            details::valid_service_option_meta_type {};\n        /** @endcond */\n    };\n\n    /**\n     * @brief a service with zero or more characteristics\n     *\n     * In GATT, a service groups a set of characteristics to something that is usefull as a group. For example, having a quadcopter, it would\n     * make sense to group the x, y and z position of the quadcopter to a quadcopter position service. All characteristics that should be\n     * part of the service, must be given as template parameter.\n     *\n     * Example:\n     * @code\n     * typedef bluetoe::service<\n     *     bluetoe::characteristic<\n     *         bluetoe::bind_characteristic_value< std::int64_t, &x_pos >,\n     *         bluetoe::characteristic_name< x_pos_name >\n     *     >,\n     *     bluetoe::characteristic<\n     *         bluetoe::bind_characteristic_value< std::int64_t, &y_pos >,\n     *         bluetoe::characteristic_name< y_pos_name >\n     *     >,\n     *     bluetoe::characteristic<\n     *         bluetoe::bind_characteristic_value< std::int64_t, &z_pos >,\n     *         bluetoe::characteristic_name< z_pos_name >\n     *     >,\n     *     bluetoe::service_uuid< 0xA0C271BF, 0xBD17, 0x4627, 0xB5DF, 0x5E26AA194920 >\n     * > quadcopter_position_service;\n     * @endcode\n     *\n     * To identify a service, every service have to have a unique UUID. 128 bit UUIDs are used for custiom services,\n     * while the shorter 16 bit UUIDs are used to identify services that have a special meaning the is documented\n     * in <a href=\"https://developer.bluetooth.org/gatt/services/Pages/ServicesHome.aspx?_ga=1.140855218.1800461708.1407160742\">specifications</a>\n     * writen by the bluetooth special interrest group.\n     * So every service must have either a service_uuid or a service_uuid16 as template parameter. The position of the UUID parameter is irelevant.\n     * A GATT client can use this UUID to identify the service; in the example above, a GATT client would look for a service with the UUID\n     * A0C271BF-BD17-4627-B5DF-5E26AA194920 to find the position service of the quadcopter.\n     *\n     * @sa server\n     * @sa secondary_service\n     * @sa is_secondary_service\n     * @sa characteristic\n     * @sa service_uuid\n     * @sa service_uuid16\n     * @sa include_service\n     * @sa requires_encryption\n     * @sa attribute_handle\n     */\n    template < typename ... Options >\n    class service\n    {\n    public:\n        /** @cond HIDDEN_SYMBOLS */\n        typedef typename details::find_all_by_meta_type< details::characteristic_meta_type, Options... >::type  characteristics;\n\n        typedef typename details::find_by_meta_type< details::service_uuid_meta_type, Options... >::type        uuid;\n\n        static_assert( !std::is_same< uuid, details::no_such_type >::value, \"Please provide a UUID to the service (service_uuid or service_uuid16 for example).\" );\n\n        static constexpr std::size_t number_of_service_attributes        = details::count_service_attributes< Options... >::number_of_attributes;\n        static constexpr std::size_t number_of_characteristic_attributes = details::sum_by< characteristics, details::sum_by_attributes >::value;\n        static constexpr std::size_t number_of_client_configs            = details::sum_by< characteristics, details::sum_by_client_configs >::value;\n\n        using notification_priority = typename details::find_by_meta_type< details::outgoing_priority_meta_type, Options..., higher_outgoing_priority<> >::type;\n\n        static_assert( std::tuple_size< typename details::find_all_by_meta_type< details::outgoing_priority_meta_type, Options... >::type >::value <= 1,\n            \"Only one of bluetoe::higher_outgoing_priority<> or bluetoe::lower_outgoing_priority<> per service allowed!\" );\n\n        /**\n         * a service is a list of attributes\n         */\n        static constexpr std::size_t number_of_attributes =\n              number_of_service_attributes\n            + number_of_characteristic_attributes;\n\n        struct meta_type :\n            details::service_meta_type,\n            details::valid_server_option_meta_type {};\n\n        /**\n         * ClientCharacteristicIndex is the number of characteristics with a Client Characteristic Configuration attribute\n         */\n        template < typename CCCDIndices, std::size_t ClientCharacteristicIndex, typename ServiceList, typename Server >\n        static details::attribute attribute_at( std::size_t index );\n\n        /**\n         * @brief assembles one data packet for a \"Read by Group Type Response\"\n         */\n        template < typename CCCDIndices, std::size_t ClientCharacteristicIndex, typename ServiceList, typename Server = void >\n        static std::uint8_t* read_primary_service_response( std::uint8_t* output, std::uint8_t* end, std::size_t starting_index, bool is_128bit_filter, Server& server );\n\n        static_assert( std::is_same<\n                typename details::find_by_not_meta_type<\n                    details::valid_service_option_meta_type,\n                    Options...\n                >::type, details::no_such_type\n            >::value, \"Parameter passed to a service that is not a valid service option!\" );\n\n        /** @endcond */\n    };\n\n    /**\n     * @brief modifier that defines a service to be a secondary service.\n     *\n     * @sa secondary_service\n     * @sa service\n     */\n    struct is_secondary_service {\n        /** @cond HIDDEN_SYMBOLS */\n        struct meta_type :\n            details::is_secondary_service_meta_type,\n            details::valid_service_option_meta_type {};\n        /** @endcond */\n    };\n\n    /**\n     * @brief definition of a secondary service\n     *\n     * Quote from the Core Spec: A secondary service is a service that is only intended to be\n     * referenced from a primary service or another secondary service or other higher layer\n     * specification. A secondary service is only relevant in the context of the entity that\n     * references it.\n     *\n     * @sa service\n     * @sa include_service\n     */\n    template < typename ... Options >\n    struct secondary_service : service< Options..., is_secondary_service > {};\n\n    /**\n     * @brief includes an other service into the defined service\n     *\n     * The service to be included is defined by it's UUID (16-bit or 128-bit).\n     * The included service must be defined within the very same server definition.\n     * UUID is either a service_uuid<> or service_uuid16<>\n     *\n     * @sa service_uuid16\n     * @sa service_uuid\n     * @sa secondary_service\n     */\n    template < typename UUID >\n    struct include_service;\n\n    template <\n        std::uint32_t A,\n        std::uint16_t B,\n        std::uint16_t C,\n        std::uint16_t D,\n        std::uint64_t E >\n    struct include_service< service_uuid< A, B, C, D, E > >\n    {\n        /** @cond HIDDEN_SYMBOLS */\n        struct meta_type :\n            details::include_service_meta_type,\n            details::valid_service_option_meta_type {};\n        /** @endcond */\n    };\n\n    template < std::uint64_t UUID >\n    struct include_service< service_uuid16< UUID > >\n    {\n        /** @cond HIDDEN_SYMBOLS */\n        struct meta_type :\n            details::include_service_meta_type,\n            details::valid_service_option_meta_type {};\n        /** @endcond */\n    };\n\n    /**\n     * @example include_example.cpp\n     * This examples shows, how to define a secondary service and how to include it in an other service.\n     */\n\n    /** @cond HIDDEN_SYMBOLS */\n\n    // service implementation\n    namespace details {\n        template < typename ... Options >\n        using attribute_generation_parameters = typename\n                add_type<\n                    service_defintion_tag, // force generation of service generation attribute\n                    typename find_all_by_meta_type<\n                        include_service_meta_type,\n                        Options...\n                    >::type\n                >::type;\n    }\n\n    template < typename ... Options >\n    template < typename CCCDIndices, std::size_t ClientCharacteristicIndex, typename ServiceList, typename Server >\n    details::attribute service< Options... >::attribute_at( std::size_t index )\n    {\n        assert( index < number_of_attributes );\n\n        using attribute_generator = details::generate_attribute_list< details::attribute_generation_parameters< Options... >, CCCDIndices, ClientCharacteristicIndex, service< Options... >, Server, std::tuple< Options..., ServiceList > >;\n\n        if ( index < number_of_service_attributes )\n            return attribute_generator::attribute_at( index );\n\n        return details::attribute_at_list< characteristics, CCCDIndices, ClientCharacteristicIndex, service< Options... >, Server >::attribute_at( index - number_of_service_attributes );\n    }\n\n    template < typename ... Options >\n    template < typename CCCDIndices, std::size_t ClientCharacteristicIndex, typename ServiceList, typename Server >\n    std::uint8_t* service< Options... >::read_primary_service_response( std::uint8_t* output, std::uint8_t* end, std::size_t starting_index, bool is_128bit_filter, Server& server )\n    {\n        const std::size_t attribute_data_size = is_128bit_filter ? 16 + 4 : 2 + 4;\n        using mapping = typename Server::handle_mapping;\n\n        if ( is_128bit_filter == uuid::is_128bit && static_cast< std::size_t >( end - output ) >= attribute_data_size )\n        {\n            std::uint8_t* const old_output = output;\n\n            output = details::write_handle( output, mapping::handle_by_index( starting_index ) );\n            output = details::write_handle( output, mapping::handle_by_index( starting_index + number_of_attributes -1 ) );\n\n            const details::attribute primary_service = attribute_at< CCCDIndices, ClientCharacteristicIndex, ServiceList, Server >( 0 );\n\n            auto read = details::attribute_access_arguments::read( output, end, 0,\n                            details::client_characteristic_configuration(),\n                            connection_security_attributes(),\n                            &server );\n\n            if ( primary_service.access( read, 1 ) == details::attribute_access_result::success )\n            {\n                output += read.buffer_size;\n            }\n            else\n            {\n                output = old_output;\n            }\n        }\n\n        return output;\n    }\n\n    namespace details {\n\n        template < typename ServiceList, typename UUID >\n        struct find_service_by_uuid\n        {\n            template < class T >\n            struct equal_uuid : std::is_same< typename T::uuid, UUID > {};\n\n            typedef typename find_if< ServiceList, equal_uuid >::type type;\n        };\n\n        template < typename ServiceList, typename Service, std::uint16_t Handle = 1 >\n        struct service_handles;\n\n        template < typename Service, typename ... Ss, std::uint16_t Handle >\n        struct service_handles< std::tuple< Service, Ss... >, Service, Handle >\n        {\n            static constexpr std::uint16_t service_attribute_handle = Handle;\n            static constexpr std::uint16_t end_service_handle       = Handle + Service::number_of_attributes - 1;\n        };\n\n        template < typename Service, typename S, typename ... Ss, std::uint16_t Handle >\n        struct service_handles< std::tuple< S, Ss... >, Service, Handle >\n        {\n            typedef service_handles< std::tuple< Ss... >, Service, Handle + S::number_of_attributes > next;\n\n            static constexpr std::uint16_t service_attribute_handle = next::service_attribute_handle;\n            static constexpr std::uint16_t end_service_handle       = next::end_service_handle;\n        };\n\n        /*\n         * service declaration\n         */\n        template < typename CCCDIndices, std::size_t ClientCharacteristicIndex, typename ServiceUUID, typename Server, typename ... Options >\n        struct generate_attribute< service_defintion_tag, CCCDIndices, ClientCharacteristicIndex, ServiceUUID, Server, Options... >\n        {\n            static attribute_access_result access( attribute_access_arguments& args, std::size_t )\n            {\n                typedef typename find_by_meta_type< service_uuid_meta_type, Options... >::type uuid;\n\n                if ( args.type == attribute_access_type::read )\n                {\n                    if ( args.buffer_offset > sizeof( uuid::bytes ) )\n                        return attribute_access_result::invalid_offset;\n\n                    args.buffer_size = std::min< std::size_t >( sizeof( uuid::bytes ) - args.buffer_offset, args.buffer_size );\n\n                    std::copy( std::begin( uuid::bytes ) + args.buffer_offset , std::begin( uuid::bytes ) + args.buffer_offset + args.buffer_size, args.buffer );\n\n                    return attribute_access_result::success;\n                }\n                else if ( args.type == attribute_access_type::compare_value )\n                {\n                    if ( sizeof( uuid::bytes ) == args.buffer_size\n                      && std::equal( std::begin( uuid::bytes ), std::end( uuid::bytes ), &args.buffer[ 0 ] ) )\n                    {\n                        return attribute_access_result::value_equal;\n                    }\n                }\n\n                return attribute_access_result::write_not_permitted;\n            }\n\n            static const attribute attr;\n        };\n\n        template < typename CCCDIndices, std::size_t ClientCharacteristicIndex, typename ServiceUUID, typename Server, typename ... Options >\n        constexpr attribute generate_attribute< service_defintion_tag, CCCDIndices, ClientCharacteristicIndex, ServiceUUID, Server, Options... >::attr {\n            bits( has_option< is_secondary_service, Options... >::value\n                ? gatt_uuids::secondary_service\n                : gatt_uuids::primary_service ),\n            &generate_attribute< service_defintion_tag, CCCDIndices, ClientCharacteristicIndex, ServiceUUID, Server, Options... >::access\n        };\n\n        /*\n         * include attribute for 16-bit includes\n         */\n        template <\n            std::uint64_t UUID,\n            typename CCCDIndices,\n            std::size_t ClientCharacteristicIndex,\n            typename ServiceUUID,\n            typename Server,\n            typename ... Options >\n        struct generate_attribute< include_service< service_uuid16< UUID > >, CCCDIndices, ClientCharacteristicIndex, ServiceUUID, Server, Options... >\n        {\n            typedef typename last_from_pack< Options... >::type service_list;\n            typedef typename find_service_by_uuid< service_list, service_uuid16< UUID > >::type included_service;\n\n            static_assert( !std::is_same< included_service, no_such_type >::value, \"The included service is was not found by UUID, please add the referenced service.\" );\n\n            typedef service_handles< service_list, included_service > handles;\n\n            static details::attribute_access_result access( attribute_access_arguments& args, std::size_t )\n            {\n                static constexpr std::uint8_t value[] = {\n                    handles::service_attribute_handle & 0xff,\n                    handles::service_attribute_handle >> 8,\n                    handles::end_service_handle & 0xff,\n                    handles::end_service_handle >> 8,\n                    UUID & 0xff,\n                    UUID >> 8\n                };\n\n                return attribute_value_read_only_access( args, &value[ 0 ], sizeof( value ) );\n            }\n\n            static const attribute attr;\n        };\n\n        template <\n            std::uint64_t UUID,\n            typename CCCDIndices,\n            std::size_t ClientCharacteristicIndex,\n            typename ServiceUUID,\n            typename Server,\n            typename ... Options >\n        constexpr attribute generate_attribute< include_service< service_uuid16< UUID > >, CCCDIndices, ClientCharacteristicIndex, ServiceUUID, Server, Options... >::attr =\n        {\n            bits( details::gatt_uuids::include ),\n            &generate_attribute< include_service< service_uuid16< UUID > >, CCCDIndices, ClientCharacteristicIndex, Options... >::access\n        };\n\n        /*\n         * include attribute for 128-bit includes\n         */\n        template <\n            std::uint32_t A,\n            std::uint16_t B,\n            std::uint16_t C,\n            std::uint16_t D,\n            std::uint64_t E,\n            typename CCCDIndices,\n            std::size_t ClientCharacteristicIndex,\n            typename ServiceUUID,\n            typename Server,\n            typename ... Options >\n        struct generate_attribute< include_service< service_uuid< A, B, C, D, E > >, CCCDIndices, ClientCharacteristicIndex, ServiceUUID, Server, Options... >\n        {\n            typedef typename last_from_pack< Options... >::type service_list;\n            typedef typename find_service_by_uuid< service_list, service_uuid< A, B, C, D, E > >::type included_service;\n\n            static_assert( !std::is_same< included_service, no_such_type >::value, \"The included service is was not found by UUID, please add the references service.\" );\n\n            typedef service_handles< service_list, included_service > handles;\n\n            static details::attribute_access_result access( attribute_access_arguments& args, std::size_t )\n            {\n                static constexpr std::uint8_t value[] = {\n                    handles::service_attribute_handle & 0xff,\n                    handles::service_attribute_handle >> 8,\n                    handles::end_service_handle & 0xff,\n                    handles::end_service_handle >> 8,\n                };\n\n                return attribute_value_read_only_access( args, &value[ 0 ], sizeof( value ) );\n            }\n\n            static const attribute attr;\n        };\n\n        template <\n            std::uint32_t A,\n            std::uint16_t B,\n            std::uint16_t C,\n            std::uint16_t D,\n            std::uint64_t E,\n            typename CCCDIndices,\n            std::size_t ClientCharacteristicIndex,\n            typename ServiceUUID,\n            typename Server,\n            typename ... Options >\n        constexpr attribute generate_attribute< include_service< service_uuid< A, B, C, D, E > >, CCCDIndices, ClientCharacteristicIndex, ServiceUUID, Server, Options... >::attr {\n            bits( details::gatt_uuids::include ),\n            &generate_attribute< include_service< service_uuid< A, B, C, D, E > >, CCCDIndices, ClientCharacteristicIndex, ServiceUUID, Server, Options... >::access\n        };\n\n        template < typename ... Options >\n        struct count_service_attributes{\n            enum {\n                number_of_attributes = std::tuple_size< attribute_generation_parameters< Options... > >::value\n            };\n        };\n\n\n    }\n    /** @endcond */\n}\n\n#endif\n"
  },
  {
    "path": "bluetoe/service_uuid.hpp",
    "content": "#ifndef BLUETOE_SERVICE_UUID_HPP\n#define BLUETOE_SERVICE_UUID_HPP\n\nnamespace bluetoe {\nnamespace details {\n    struct service_uuid_meta_type {};\n    struct service_uuid_16_meta_type : service_uuid_meta_type {};\n    struct service_uuid_128_meta_type : service_uuid_meta_type {};\n}\n}\n\n#endif // include guard\n"
  },
  {
    "path": "bluetoe/services/CMakeLists.txt",
    "content": "add_library(bluetoe_services INTERFACE)\nadd_library(bluetoe::services ALIAS bluetoe_services)\ntarget_include_directories(bluetoe_services INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})\n"
  },
  {
    "path": "bluetoe/services/bas.hpp",
    "content": "#ifndef BLUTOE_SERVICES_BAS_HPP\n\n#include <bluetoe/service.hpp>\n#include <bluetoe/mixin.hpp>\n#include <type_traits>\n\nnamespace bluetoe\n{\n    namespace bas\n    {\n        /**\n         * @brief UUID of a Battery Service (BAS)\n         */\n        using service_uuid = service_uuid16< 0x180F >;\n\n        /**\n         * @brief UUID of a level characteristic\n         */\n        using level_uuid = characteristic_uuid16< 0x2A19 >;\n\n        namespace details {\n            /** @cond HIDDEN_SYMBOLS */\n            struct handler_tag {};\n            struct no_battery_level_notifications_tag {};\n            struct valid_bas_service_option_tag {};\n\n            template < typename Handler >\n            struct handler_impl\n            {\n                struct read_handler : bluetoe::details::value_handler_base\n                {\n                    template < class Server >\n                    static std::uint8_t call_read_handler( std::size_t offset, std::size_t, std::uint8_t* out_buffer, std::size_t& out_size, void* server )\n                    {\n                        if ( offset != 0 )\n                            return bluetoe::error_codes::attribute_not_long;\n\n                        Handler& handler = static_cast< Handler& >( *static_cast< Server* >( server ) );\n\n                        const int value = handler.read_battery_level();\n                        assert(value >= 0);\n                        assert(value <= 100);\n\n                        *out_buffer = static_cast< std::uint8_t >( value );\n                        out_size = 1;\n\n                        return bluetoe::error_codes::success;\n                    }\n\n                    struct meta_type :\n                        bluetoe::details::value_handler_base::meta_type,\n                        bluetoe::details::characteristic_value_read_handler_meta_type {};\n                };\n\n                template < typename Server >\n                void notifiy_battery_level( Server& srv )\n                {\n                    srv.template notify< level_uuid >();\n                }\n            };\n\n            template < typename, typename >\n            struct service_impl;\n\n            template < typename Handler, typename ... Options >\n            struct service_impl< Handler, std::tuple< Options... > >\n            {\n                using type =\n                    bluetoe::service<\n                        service_uuid,\n                        bluetoe::characteristic<\n                            level_uuid,\n                            typename handler_impl< Handler >::read_handler,\n                            bluetoe::notify,\n                            bluetoe::notify_on_subscription\n                        >,\n                        bluetoe::mixin< handler_impl< Handler > >,\n                        Options...\n                    >;\n            };\n\n\n            template < typename ... Options >\n            struct calculate_service {\n                using handler = typename bluetoe::details::find_by_meta_type< handler_tag, Options... >::type;\n\n                static_assert( !std::is_same< handler, bluetoe::details::no_such_type >::value, \"bas::handler<> is required\" );\n\n                using other_args = typename bluetoe::details::find_all_by_not_meta_type<\n                    details::valid_bas_service_option_tag, Options... >::type;\n\n                using type = typename service_impl< typename handler::type, other_args >::type;\n            };\n            /** @endcond */\n        }\n\n        /**\n         * @brief indicates no support for battery level notifications\n         *\n         * If this option is given to battery_level, then the implementation of the server\n         * will not implement notifications for this service.\n         *\n         * @todo Not implemented yet\n         */\n        struct no_battery_level_notifications {\n            /** @cond HIDDEN_SYMBOLS */\n            struct meta_type : details::no_battery_level_notifications_tag\n                             , details::valid_bas_service_option_tag {};\n            /** @endcond */\n        };\n\n        /**\n         * @brief pass a handler to the service\n         *\n         * The handler have to provide a single function with the following name and type:\n         *\n         * @code\n         * int read_battery_level();\n         * @endcode\n         *\n         * Use bluetoe::mixin to inject an instance of that handler into the GATT server.\n         */\n        template < typename Handler >\n        struct handler {\n            /** @cond HIDDEN_SYMBOLS */\n            using type = Handler;\n\n            struct meta_type : details::handler_tag\n                             , details::valid_bas_service_option_tag {};\n            /** @endcond */\n        };\n    }\n\n    /**\n     * @brief implementation of the Battery Service\n     *\n     * To adapt the measured battery level to the GATT service,\n     * a handler have to be provided, that can be called, to\n     * measure the battery level.\n     *\n     * A bluetoe::server<> instance that contains a battery service, implements\n     * a function `void notifiy_battery_level(GATTServer&)`, that will request a notification\n     * of the battery level characteristic. If the no_battery_level_notifications\n     * option is given, this function will not be implemeted.\n     *\n     * @sa bluetoe::bas::no_battery_level_notifications\n     * @sa bluetoe::bas::handler\n     */\n    template < typename ... Options >\n    using battery_level = typename bas::details::calculate_service< Options... >::type;\n}\n\n#endif\n"
  },
  {
    "path": "bluetoe/services/bootloader.hpp",
    "content": "#ifndef BLUETOE_SERVICES_BOOTLOADER_HPP\n#define BLUETOE_SERVICES_BOOTLOADER_HPP\n\n#include <bluetoe/service.hpp>\n#include <bluetoe/mixin.hpp>\n#include <algorithm>\n\n/**\n * @file services/bootloader.hpp\n *\n * This is the implementation of a bootloader as a Bluetooth LE service.\n * The service contains two characteristics. A control point to inquire informations and to control the flash process.\n * One data characteristic to upload and download larger amounts of data.\n *\n * \\ref Bootloader-Protocol\n */\nnamespace bluetoe\n{\n    namespace bootloader {\n\n        /** @cond HIDDEN_SYMBOLS */\n        namespace details {\n            struct handler_meta_type {};\n            struct memory_region_meta_type {};\n            struct page_size_meta_type {};\n        }\n        /** @endcond */\n\n        /**\n         * @brief required parameter to define the size of a page\n         */\n        template < std::size_t PageSize >\n        struct page_size\n        {\n           /** @cond HIDDEN_SYMBOLS */\n            typedef details::page_size_meta_type meta_type;\n            static constexpr std::size_t value = PageSize;\n            /** @endcond */\n        };\n\n        /**\n         * @brief denoting a memory range with it's start address and endaddress (exklusive)\n         *\n         * So memory_region< 0x1000, 0x2000 > means all bytes with the address from 0x1000\n         * to 0x2000 but _not_ 0x2000.\n         */\n        template < std::uintptr_t Start, std::uintptr_t End >\n        struct memory_region {};\n\n        /**\n         * @brief a list of all memory regions that are flashable by the bootloader\n         */\n        template < typename ... Regions >\n        struct white_list;\n\n        /** @cond HIDDEN_SYMBOLS */\n        template < std::uintptr_t Start, std::uintptr_t End, typename ... Regions >\n        struct white_list< memory_region< Start, End >, Regions ... >\n        {\n            static bool acceptable( std::uintptr_t start, std::uintptr_t end )\n            {\n                return ( start >= Start && end <= End )\n                    || white_list< Regions... >::acceptable( start, end );\n            }\n\n            typedef details::memory_region_meta_type meta_type;\n        };\n\n        template <>\n        struct white_list<>\n        {\n            static bool acceptable( std::uintptr_t, std::uintptr_t )\n            {\n                return false;\n            }\n\n            typedef details::memory_region_meta_type meta_type;\n        };\n        /** @endcond */\n\n        /**\n         * @brief requireded parameter to define, how the bootloader can access memory and flash\n         */\n        template < typename UserHandler >\n        struct handler {\n            /** @cond HIDDEN_SYMBOLS */\n            typedef UserHandler                 user_handler;\n            typedef details::handler_meta_type  meta_type;\n            /** @endcond */\n        };\n\n        /**\n         * @brief inform the bootloader, that an asynchrone flash operations is finished\n         */\n        template < class Server >\n        void end_flash( Server& srv )\n        {\n            srv.end_flash( srv );\n        }\n\n        /**\n         * @brief the UUID of the bootloader service is 7D295F4D-2850-4F57-B595-837F5753F8A9\n         */\n        using service_uuid       = bluetoe::service_uuid< 0x7D295F4D, 0x2850, 0x4F57, 0xB595, 0x837F5753F8A9 >;\n\n        /**\n         * @brief the UUID of the control point charateristic is 7D295F4D-2850-4F57-B595-837F5753F8A9\n         */\n        using control_point_uuid = bluetoe::characteristic_uuid< 0x7D295F4D, 0x2850, 0x4F57, 0xB595, 0x837F5753F8A9 >;\n\n        /**\n         * @brief the UUID of the data charateristic is 7D295F4D-2850-4F57-B595-837F5753F8AA\n         */\n        using data_uuid          = bluetoe::characteristic_uuid< 0x7D295F4D, 0x2850, 0x4F57, 0xB595, 0x837F5753F8AA >;\n\n        /**\n         * @brief the UUID of the data charateristic is 7D295F4D-2850-4F57-B595-837F5753F8AA\n         */\n        using progress_uuid      = bluetoe::characteristic_uuid< 0x7D295F4D, 0x2850, 0x4F57, 0xB595, 0x837F5753F8AB >;\n\n        /**\n         * @brief error codes that are used by the bootloader on the ATT layer\n         */\n        enum att_error_codes : std::uint8_t {\n            /*\n             * attempt to write or read data to or from the bootloader, while no operation is in progress\n             */\n            no_operation_in_progress = bluetoe::error_codes::application_error_start,\n            invalid_opcode,\n            invalid_state,\n            buffer_overrun_attempt\n        };\n\n        /**\n         * @brief range of error codes that can be used by the user handler to indicate the cause of an error\n         */\n        enum class error_codes : std::uint8_t {\n            /**\n             * every thing is fine.\n             */\n            success,\n\n            /**\n             * somehow the request would require more authorization\n             */\n            not_authorized,\n        };\n\n        /** @cond HIDDEN_SYMBOLS */\n        namespace details {\n\n            /**\n             * Buffer to take at max a page full of data\n             * Responsible to make sure, that full pages are flashed.\n             */\n            template < std::size_t PageSize >\n            class flash_buffer\n            {\n            public:\n                flash_buffer()\n                    : state_( idle )\n                    , ptr_( 0 )\n                {\n                }\n\n                std::uint32_t free_size() const\n                {\n                    return state_ == filling\n                        ? PageSize - ptr_\n                        : 0;\n                }\n\n                template < class Handler >\n                void set_start_address( std::uintptr_t address, Handler& h, std::uint32_t checksum, std::uint16_t cons )\n                {\n                    assert( state_ == idle );\n                    state_          = filling;\n                    ptr_            = address % PageSize;\n                    addr_           = address - ptr_;\n                    crc_            = checksum;\n                    consecutive_    = cons;\n\n                    h.read_mem( addr_, ptr_, &buffer_[ 0 ] );\n                }\n\n                template < class Handler >\n                std::size_t write_data( std::size_t write_size, const std::uint8_t* value, Handler& h )\n                {\n                    assert( state_ == filling );\n                    assert( ptr_ != PageSize );\n\n                    const std::size_t copy_size = std::min( PageSize - ptr_, write_size );\n                    std::copy( value, value + copy_size, &buffer_[ ptr_ ] );\n                    crc_ = h.checksum32( &buffer_[ ptr_ ], copy_size, crc_ );\n\n                    ptr_ += copy_size;\n\n                    if ( ptr_ == PageSize )\n                    {\n                        flush( h );\n                    }\n\n                    return copy_size;\n                }\n\n                template < class Handler >\n                bool flush( Handler& h )\n                {\n                    if ( state_ != filling || ptr_ == 0 )\n                        return false;\n\n                    state_ = flashing;\n\n                    // no unnessary calls to user handler\n                    if ( PageSize !=  ptr_ )\n                        h.read_mem( addr_ + ptr_, PageSize - ptr_, &buffer_[ ptr_ ] );\n\n                    h.start_flash( addr_, &buffer_[ 0 ], PageSize );\n\n                    return true;\n                }\n\n                std::uint32_t crc() const\n                {\n                    return crc_;\n                }\n\n                void free()\n                {\n                    state_ = idle;\n                    ptr_   = 0;\n                }\n\n                bool empty() const\n                {\n                    return state_ == idle;\n                }\n\n                std::uint16_t consecutive() const\n                {\n                    return consecutive_;\n                }\n            private:\n                enum {\n                    idle,\n                    filling,\n                    flashing\n                } state_;\n\n                std::uintptr_t  addr_;\n                std::size_t     ptr_;\n                std::uint32_t   crc_;\n                std::uint8_t    buffer_[ PageSize ];\n                std::uint16_t   consecutive_;\n            };\n\n            enum opcode : std::uint8_t\n            {\n                opc_get_version,\n                opc_get_crc,\n                opc_get_sizes,\n                opc_start_flash,\n                opc_stop_flash,\n                opc_flush,\n                opc_start,\n                opc_reset,\n                opc_read,\n                undefined_opcode = 0xff\n            };\n\n            enum data_code : std::uint8_t\n            {\n                success         = 1,\n            };\n\n            template < typename UserHandler, typename MemRegions, std::size_t PageSize >\n            class controller : public UserHandler\n            {\n            public:\n                controller()\n                    : opcode( undefined_opcode )\n                    , start_address( 0 )\n                    , end_address( 0 )\n                    , check_sum( 0 )\n                    , in_flash_mode( false )\n                    , next_buffer_( 0 )\n                    , used_buffer_( 0 )\n                    , consecutive_( 0 )\n                {\n                }\n\n                std::uintptr_t read_address( const std::uint8_t* rend )\n                {\n                    std::uintptr_t result = 0;\n                    for ( const std::uint8_t* rbegin = rend + sizeof( std::uint8_t* ); rbegin != rend; --rbegin )\n                    {\n                        result = result << 8;\n                        result |= *( rbegin -1 );\n                    }\n\n                    return result;\n                }\n\n                std::pair< std::uint8_t, bool > bootloader_write_control_point( std::size_t write_size, const std::uint8_t* value )\n                {\n                    if ( write_size < 1 )\n                        return std::make_pair( bluetoe::error_codes::invalid_attribute_value_length, false );\n\n                    opcode = *value;\n\n                    switch ( opcode )\n                    {\n                    case opc_get_version:\n                    case opc_get_sizes:\n                    case opc_stop_flash:\n                        {\n                            if ( write_size != 1 )\n                                return request_error( bluetoe::error_codes::invalid_attribute_value_length );\n\n                            in_flash_mode = false;\n                            next_buffer_  = 0;\n                            used_buffer_  = 0;\n\n                            for ( auto& buffer : buffers_ )\n                                buffer.free();\n                        }\n                        break;\n                    case opc_get_crc:\n                        {\n                            if ( write_size != 1 + 2 * sizeof( std::uint8_t* ) )\n                                return request_error( bluetoe::error_codes::invalid_attribute_value_length );\n\n                                                 start_address = read_address( value +1 );\n                            const std::uintptr_t end_address   = read_address( value +1 + sizeof( std::uint8_t* ) );\n\n                            if ( start_address > end_address || !MemRegions::acceptable( start_address,end_address ) )\n                                return request_error( bluetoe::error_codes::invalid_offset );\n\n                            check_sum = this->public_checksum32( start_address, end_address - start_address );\n                        }\n                        break;\n                    case opc_start_flash:\n                        {\n                            if ( write_size != 1 + sizeof( std::uint8_t* ) )\n                                return request_error( bluetoe::error_codes::invalid_attribute_value_length );\n\n                            start_address = read_address( value +1 );\n                            check_sum     = this->checksum32( start_address );\n                            consecutive_  = 0;\n                            next_buffer_  = 0;\n                            used_buffer_  = 0;\n                            in_flash_mode = true;\n\n                            if ( !MemRegions::acceptable( start_address, start_address ) )\n                                return request_error( bluetoe::error_codes::invalid_offset );\n\n                            for ( auto& buffer : buffers_ )\n                                buffer.free();\n\n                            buffers_[next_buffer_].set_start_address( start_address, *this, check_sum, consecutive_ );\n                        }\n                        break;\n                    case opc_flush:\n                        {\n                            if ( !in_flash_mode )\n                                return request_error( invalid_state );\n\n                            if ( !buffers_[next_buffer_].flush( *this ) )\n                                return request_error( invalid_state );\n\n                            return std::pair< std::uint8_t, bool >{ bluetoe::error_codes::success, true };\n                        }\n                        break;\n                    case opc_start:\n                        {\n                            if ( write_size != 1 + sizeof( std::uint8_t* ) )\n                                return request_error( bluetoe::error_codes::invalid_attribute_value_length );\n\n                            const std::uintptr_t start_address = read_address( value +1 );\n\n                            this->run( start_address );\n                        }\n                        break;\n                    case opc_reset:\n                        {\n                            if ( write_size != 1 )\n                                return request_error( bluetoe::error_codes::invalid_attribute_value_length );\n\n                            this->reset();\n                        }\n                        break;\n                    case opc_read:\n                        {\n                            error         = error_codes::success;\n                            start_address = read_address( value +1 );\n                            end_address   = read_address( value +1 + sizeof( std::uint8_t* ) );\n                            check_sum     = this->checksum32( start_address );\n\n                            if ( start_address > end_address || !MemRegions::acceptable( start_address,end_address ) )\n                                return request_error( bluetoe::error_codes::invalid_offset );\n\n                            if ( start_address != end_address )\n                            {\n                                this->data_indication_call_back();\n\n                                return std::pair< std::uint8_t, bool >{ bluetoe::error_codes::success, false };\n                            }\n                        }\n                        break;\n                    default:\n                        return std::pair< std::uint8_t, bool >{ att_error_codes::invalid_opcode, false };\n                    }\n\n                    return std::pair< std::uint8_t, bool >{ bluetoe::error_codes::success, true };\n                }\n\n                std::uint8_t bootloader_read_control_point( std::size_t read_size, std::uint8_t* out_buffer, std::size_t& out_size )\n                {\n                    assert( read_size >= 20 );\n                    *out_buffer = opcode;\n\n                    switch ( opcode )\n                    {\n                    case opc_get_version:\n                        {\n                            const std::pair< const std::uint8_t*, std::size_t > version = this->get_version();\n                            out_size = std::min( read_size, version.second + 1 );\n\n                            *out_buffer = opc_get_version;\n                            std::copy( version.first, version.first + out_size - 1, out_buffer + 1 );\n                        }\n                        break;\n                    case opc_get_crc:\n                        {\n                            bluetoe::details::write_32bit( out_buffer + 1, check_sum );\n                            out_size = sizeof( std::uint8_t ) + sizeof( std::uint32_t );\n                        }\n                        break;\n                    case opc_get_sizes:\n                        {\n                            std::uint8_t* out = out_buffer;\n                            ++out;\n                            *out = sizeof( std::uint8_t* );\n                            ++out;\n                            out = bluetoe::details::write_32bit( out, PageSize );\n                            out = bluetoe::details::write_32bit( out, number_of_concurrent_flashs );\n\n                            out_size = out - out_buffer;\n                        }\n                        break;\n                    case opc_start_flash:\n                        {\n                            std::uint8_t* out = out_buffer;\n                            ++out;\n                            *out = read_size + 3;\n                            ++out;\n                            out = bluetoe::details::write_32bit( out, buffers_[next_buffer_].crc() );\n\n                            out_size = out - out_buffer;\n                        }\n                        break;\n                    case opc_stop_flash:\n                        out_size = 1;\n                        break;\n                    case opc_flush:\n                        {\n                            std::uint8_t* out = out_buffer;\n                            ++out;\n                            out = bluetoe::details::write_32bit( out, buffers_[next_buffer_].crc() );\n                            out = bluetoe::details::write_16bit( out, buffers_[next_buffer_].consecutive() );\n\n                            out_size = out - out_buffer;\n                        }\n                        break;\n                    case opc_read:\n                        {\n                            std::uint8_t* out = out_buffer;\n                            ++out;\n                            out = bluetoe::details::write_32bit( out, check_sum );\n                            *out = static_cast< std::uint8_t >( error );\n                            ++out;\n\n                            out_size = out - out_buffer;\n                        }\n                        break;\n                    }\n\n                    return bluetoe::error_codes::success;\n                }\n\n                std::uint8_t bootloader_write_data( std::size_t write_size, const std::uint8_t* value )\n                {\n                    if ( !in_flash_mode )\n                        return no_operation_in_progress;\n\n                    if ( write_size == 0 )\n                        return bluetoe::error_codes::success;\n\n                    if ( buffers_[ next_buffer_ ].free_size() == 0 && !find_next_buffer( start_address ) )\n                        return buffer_overrun_attempt;\n\n                    while ( write_size )\n                    {\n                        const std::size_t moved = buffers_[ next_buffer_ ].write_data( write_size, value, *this );\n\n                        value           += moved;\n                        write_size      -= moved;\n                        start_address   += moved;\n\n                        if ( write_size && !find_next_buffer( start_address ) )\n                            return buffer_overrun_attempt;\n                    }\n\n                    return bluetoe::error_codes::success;\n                }\n\n                std::uint8_t bootloader_read_data( std::size_t read_size, std::uint8_t* out_buffer, std::size_t& out_size )\n                {\n                    if ( opcode == opc_read )\n                    {\n                        out_size  = std::min( read_size, end_address - start_address );\n\n                        error     = this->public_read_mem( start_address, out_size, out_buffer );\n\n                        if ( error == error_codes::success )\n                        {\n                            check_sum = this->checksum32( out_buffer, out_size, check_sum );\n                            start_address += out_size;\n                        }\n                        else\n                        {\n                            out_size = 0;\n                        }\n\n                        if ( start_address == end_address || error != error_codes::success )\n                        {\n                            this->control_point_notification_call_back();\n                        }\n                        else\n                        {\n                            this->data_indication_call_back();\n                        }\n                    }\n\n                    return bluetoe::error_codes::success;\n                }\n\n                std::uint8_t bootloader_progress_data( std::size_t read_size, std::uint8_t* out_buffer, std::size_t& out_size )\n                {\n                    buffers_[used_buffer_].free();\n                    out_size = 7;\n                    assert( read_size >= out_size );\n\n                    out_buffer = bluetoe::details::write_32bit( out_buffer, buffers_[used_buffer_].crc() );\n                    out_buffer = bluetoe::details::write_16bit( out_buffer, buffers_[used_buffer_].consecutive() );\n\n                    // trick: that's the link layers MTU size:\n                    *out_buffer = read_size + 3;\n                    ++out_buffer;\n\n                    used_buffer_ = ( used_buffer_ + 1 ) % number_of_concurrent_flashs;\n\n                    return bluetoe::error_codes::success;\n                }\n\n                template < class Server >\n                void end_flash( Server& server )\n                {\n                    server.template notify< progress_uuid >();\n                }\n\n                template < class Server >\n                void bootloader_control_point_notification( Server& server )\n                {\n                    server.template notify< control_point_uuid >();\n                }\n\n                template < class Server >\n                void bootloader_data_indication( Server& server )\n                {\n                    server.template indicate< data_uuid >();\n                }\n\n            private:\n                std::uint32_t free_size() const\n                {\n                    std::uint32_t result = 0;\n\n                    for ( const auto& b : buffers_ )\n                        result += b.free_size();\n\n                    return result;\n                }\n\n                bool find_next_buffer( std::size_t start_address )\n                {\n                    const auto next = ( next_buffer_ + 1 ) % number_of_concurrent_flashs;\n\n                    if ( buffers_[ next ].empty() )\n                    {\n                        ++consecutive_;\n                        buffers_[ next ].set_start_address( start_address, *this, buffers_[ next_buffer_ ].crc(), consecutive_ );\n                        next_buffer_ = next;\n\n                        return true;\n                    }\n\n                    return false;\n                }\n\n                std::pair< std::uint8_t, bool > request_error( std::uint8_t code )\n                {\n                    opcode          = undefined_opcode;\n                    in_flash_mode   = false;\n\n                    return std::pair< std::uint8_t, bool >{ code, false };\n                }\n\n                std::uint8_t                    opcode;\n                std::uintptr_t                  start_address;\n                std::uintptr_t                  end_address;\n                error_codes                     error;\n                std::uint32_t                   check_sum;\n                bool                            in_flash_mode;\n\n                static constexpr std::size_t    number_of_concurrent_flashs = 2;\n                unsigned                        next_buffer_;\n                unsigned                        used_buffer_;\n                std::uint16_t                   consecutive_;\n                flash_buffer< PageSize >        buffers_[number_of_concurrent_flashs];\n            };\n\n            template < typename ... Options >\n            struct calculate_service {\n                using page_size    = typename bluetoe::details::find_by_meta_type< page_size_meta_type, Options... >::type;\n\n                static_assert( !std::is_same< bluetoe::details::no_such_type, page_size >::value,\n                    \"Please use page_size<> to define the block size of the flash.\" );\n\n                using mem_regions  = typename bluetoe::details::find_by_meta_type< memory_region_meta_type, Options... >::type;\n\n                static_assert( !std::is_same< bluetoe::details::no_such_type, mem_regions >::value,\n                    \"Please use white_list or black_list, to define accessable memory regions.\" );\n\n                using user_handler = typename bluetoe::details::find_by_meta_type< handler_meta_type, Options... >::type;\n\n                static_assert( !std::is_same< bluetoe::details::no_such_type, user_handler >::value,\n                    \"To use the bootloader, please provide a handler<> that fullfiles the requirements documented with bootloader_handler_prototype.\" );\n\n                using implementation = controller< typename user_handler::user_handler, mem_regions, page_size::value >;\n\n                using type = bluetoe::service<\n                    bluetoe::bootloader::service_uuid,\n                    bluetoe::characteristic<\n                        bluetoe::bootloader::control_point_uuid,\n                        bluetoe::mixin_write_notification_control_point_handler<\n                            implementation, &implementation::bootloader_write_control_point, bluetoe::bootloader::control_point_uuid\n                        >,\n                        bluetoe::mixin_read_handler<\n                            implementation, &implementation::bootloader_read_control_point\n                        >,\n                        bluetoe::no_read_access,\n                        bluetoe::notify,\n                        bluetoe::write_without_response\n                    >,\n                    bluetoe::characteristic<\n                        bluetoe::bootloader::data_uuid,\n                        bluetoe::mixin_write_handler<\n                            implementation, &implementation::bootloader_write_data\n                        >,\n                        bluetoe::mixin_read_handler<\n                            implementation, &implementation::bootloader_read_data\n                        >,\n                        bluetoe::no_read_access,\n                        bluetoe::indicate,\n                        bluetoe::write_without_response\n                    >,\n                    bluetoe::characteristic<\n                        bluetoe::bootloader::progress_uuid,\n                        bluetoe::mixin_read_handler<\n                            implementation, &implementation::bootloader_progress_data\n                        >,\n                        bluetoe::no_read_access,\n                        bluetoe::notify\n                    >,\n                    bluetoe::mixin< implementation >\n                >;\n            };\n        }\n\n        template < typename UserHandler, typename MemRegions, std::size_t PageSize >\n        using controller = details::controller< UserHandler, MemRegions, PageSize >;\n        /** @endcond */\n\n\n        /**\n         * @brief Prototype for a handler, that adapts the bootloader service to the actual hardware\n         */\n        class bootloader_handler_prototype\n        {\n        public:\n            /**\n             * Start to flash\n             *\n             * When the hardware signals, that the memory is flashed, end_flash( server) have to be called on the server instance\n             */\n            bootloader::error_codes start_flash( std::uintptr_t address, const std::uint8_t* values, std::size_t size );\n\n            /**\n             * Run the program given at start_addr\n             */\n            bootloader::error_codes run( std::uintptr_t start_addr );\n\n            /**\n             * reset bootloader\n             */\n            bootloader::error_codes reset();\n\n            /**\n             * Return a custom string as response to the Get Version procedure.\n             * Make sure, that the response is not longer than 20 bytes, or othere wise it could get truncated on the link layer.\n             */\n            std::pair< const std::uint8_t*, std::size_t > get_version();\n\n            /**\n             * this is very handy, when it comes to testing...\n             */\n            void read_mem( std::uintptr_t address, std::size_t size, std::uint8_t* destination );\n\n            /**\n             * calculate the checksum of the given range of memory.\n             */\n            std::uint32_t checksum32( std::uintptr_t start_addr, std::size_t size );\n\n            /**\n             * adds new data to the given crc\n             */\n            std::uint32_t checksum32( const std::uint8_t* start_addr, std::size_t size, std::uint32_t old_crc );\n\n            /**\n             * special overload to calculate the CRC over a start address\n             */\n            std::uint32_t checksum32( std::uintptr_t start_addr );\n\n            /**\n             * This function is used, when reading from memory, while the Read procedure is executed.\n             *\n             * @attention Make sure, that this function does not reveal any sensitiv information.\n             *            Make sure, that address and size are resonable parameters.\n             *\n             * @return an value != error_codes::success, if read access to the given range is not possible or not authorized.\n             */\n            bootloader::error_codes public_read_mem( std::uintptr_t address, std::size_t size, std::uint8_t* destination );\n\n            /**\n             * @brief version of checksum function, that will be directly called by the execution of the\n             *        Get CRC procedure.\n             *\n             * @attention If there are ranges that contain sensitiv information, make sure, that size is large enough,\n             *            so that one can not get the content of the memory from the resulting CRC.\n             *            In case, that such an attempt is detected, return a fixed value (0 for example).\n             */\n            std::uint32_t public_checksum32( std::uintptr_t start_addr, std::size_t size );\n\n            /**\n             * @brief technical required function, that have to call bootloader_control_point_notification(), with the instance of the server\n             */\n            void control_point_notification_call_back();\n\n            /**\n             * @brief technical required function, that have to call bootloader_data_indication(), with the instance of the server\n             */\n            void data_indication_call_back();\n        };\n    }\n\n    /**\n     * @brief Implementation of a bootloader service\n     */\n    template < typename ... Options >\n    using bootloader_service = typename bootloader::details::calculate_service< Options... >::type;\n\n}\n\n#endif\n"
  },
  {
    "path": "bluetoe/services/bootloader.md",
    "content": "@section Bootloader-Protocol\n\nGATT\n====\nThe Bootloader is one service containing three characteristics. The UUID of the service is 7D295F4D-2850-4F57-B595-837F5753F8A9. The Control Point characteristic receives commands and requests and sends responds by ATT notifications. The UUID of the Control Point characeteristic is 7D295F4D-2850-4F57-B595-837F5753F8A9. The Data characteristic is used to receive data. The UUID of the Data characteristic is 7D295F4D-2850-4F57-B595-837F5753F8AA. The Progress characetistic is used to give feedback about the used buffer sizes. The UUID of the Progress characteristic is 7D295F4D-2850-4F57-B595-837F5753F8AB.\n\nThe characteristics has following properties:\n\nCharacteristic | Properties        | UUID\n---------------|-------------------|--------------------------------------\nControl Point  | Write, Write Without Response, Notify     | 7D295F4D-2850-4F57-B595-837F5753F8A9\nData           | Write, Write Without Response, Indication | 7D295F4D-2850-4F57-B595-837F5753F8AA\nProgress       | Notify            | 7D295F4D-2850-4F57-B595-837F5753F8AB\n\nProcedures\n==========\n\nThe bootloader implements following procedures:\n\nProcedure   | Description                                 | opcode | expected response code |\n------------|---------------------------------------------|-------:|-----------------------:|\nGet Version | Read a version string from the user handler |      0 |                      0 |\nGet CRC     | Calculate crc over specific area            |      1 |                      1 |\nGet Sizes   | Returns maschine specific values            |      2 |                      2 |\nStart Flash | Start to flash a memory region              |      3 |                      3 |\nStop Flash  | Stop to flash a memory region               |      4 |                      4 |\nFlush       | Flush written data to flash memory          |      5 |                      5 |\nStart       | Start a programm at a specific address      |      6 |                    n/a |\nReset       | Resets the bootloader                       |      7 |                    n/a |\nRead        | Read a memory range from the device         |      8 |                      8 |\n\nA client starts a procedure by sending an ATT Writing Request with the opcode to the Control Point, followed by the parameters that are required for the procedure. If the procedure starts successfully, the Bootloader will response with an ATT Write Response. The procedure will end by the reply of the bootloader that is send with an ATT Notification.\n\nIf there was something wrong with the start of the Control Point procedure, the bootloader will response immediately with an ATT Error Response and an error code denoting the reason for the failure. If both, bootloader and bootloader client are implemented without error, an ATT Error Response is not expected.\n\nA write to the Control Point will result in either an ATT Error Response, or in an ATT Notification. A Control Point procedure is active as long as a notification is not send out by the bootloader. There should be only one active Control Point procedured at any time. That means a bootloader client has to wait for the end of a procedure before starting the next procedure.\n\nAll parameters longer than one octet are encoded in little endian.\n\nGet Version\n-----------\nThe procedure is started by writing the opcode to the Control Point.\n\nRequest Fields     | Length | Value |\n-------------------|-------:|------:|\nOpcode             | 1      | 0     |\n\nThe response is an ATT Notification, with the response code, followed by a variable length version string.\n\nResponse Fields    | Length   | Value   |\n-------------------|---------:|--------:|\nResponse Code      | 1        | 0       |\nVersion String     | variable | Version |\n\nGet CRC\n-------\nThe procedure is started by writing the opcode, followed by the start- and end-address of the range, to the Control Point. The size of addresses depend on the target architectur and can be inquired, using the Get Sizes procedure.\n\nRequest Fields     | Length | Value |\n-------------------|-------:|------:|\nOpcode             | 1      | 1     |\nStart-Address      | sizeof( std::uint8_t* ) | first byte of the range |\nEnd-Address        | sizeof( std::uint8_t* ) | first byte behind the range |\n\nThe response is an ATT Notification, containing the response code and the 32 bit checksum.\n\nResponse Fields    | Length   | Value   |\n-------------------|---------:|--------:|\nResponse Code      | 1        | 1       |\nChecksum           | 4        | calculated checksum over the given range |\n\n### CRC Algorithm\nThe used CRC algorithm should be adler32.\n\nGet Sizes\n---------\nThe procedure is started by writing the opcode to the Control Point.\n\nRequest Fields     | Length | Value |\n-------------------|-------:|------:|\nOpcode             | 1      | 2     |\n\nThe response is an ATT Notification, containing certain machine dependen values and buffer sizes.\n\nResponse Fields    | Length   | Value   |\n-------------------|---------:|--------:|\nResponse Code      | 1        | 2       |\nAddress-Size       | 1        | sizeof( std::uint8_t* ) |\nPage-Size          | 4        | Size of a Page |\nPage Buffers       | 4        | Number of pages the bootloader can buffer |\n\nThe Address-Size is what the expression sizeof( std::uint8_t* ) evaluates to in the bootloader. It's used where ever an address have to be communicted between bootloader and bootloader client. The page size is the size of a single flash page. The number of Page Buffers denontes the amount of data the bootloader can store, before the client have to wait for buffers to become free.\n\nStart Flash\n-----------\nThe Start Flash Procedure takes an address as the first and only parameter. As the address size of the target plattform is out of the scope of the bootloader implementation, the size is equal to sizeof( std::uint8_t* ) on the bootloaders target device. The address denotes the target address of the memory contents that follows. The start address must be within the flashable ranges of the bootloader.\n\nRequest Fields     | Length | Value |\n-------------------|-------:|------:|\nOpcode             | 1      | 3     |\nStart Address      | sizeof( std::uint8_t* ) | address of the range to be flashed |\n\nThe bootloader will response with a notification that contains the response code, followed by the current ATT MTU size of the connection and a checksum that is calculated over the received address.\n\nThe MTU is send for the case, that the clients BLE API does not give access to that values. The knowlage of the value allows a client to write data in packets as big as possible (MTU-3). A client can start to write the data to be flashed directly after the Start Flash procedure was started (even before the ATT Response was received). If the client has no access to the connections MTU size and not received the Control Point procedures response, it should assume an MTU of 23.\n\nResponse Fields    | Length   | Value   |\n-------------------|---------:|--------:|\nResponse Code      | 1        | 3       |\nMTU                | 1        | >= 23   |\nChecksum           | 4        | crc(Start Address) |\n\nThe Bootloader is now in flash mode and will receive data and flash it into memory, as long as data is send to the Data characteristic or until a new control point procedure is received. The bootloader will flush data, when the received data reached the end of a page or when the Flush procedure is executed. A bootloader client shall not force a flush of data (neither implicit nor explicit) before it received the CRC of the start address to make sure, that the bootloader understood the start address correct.\n\n### Buffer Management\nThe bootloader client has to take care that the bootloaders buffers do not overflow. The number of pages and the size of a page have to be known to the bootloader client or have to be inquired, using the Get Sizes procedure. Writing data into the middle of a page buffer will allocate the part of the buffer before the start address too.\n\nThe bootloader will send ATT Notifications using the Progress characteristic, to commucate the current free buffer sizes.\n\nWhen leaving the flash mode by executing an other Control Point procedure, the next procedure will yield an error, if there was unflashed data.\n\n### Writing parts of a page\nTo flash just a part of a page, set the start address to the desired start address. The bootloader will fill the used page buffer with the content before the start address with the content of the flash before the start address. This will result in unchanged flash content before the start address.\n\nIf the range to be flashed does not end at the end address of a page (addres % page-size != 0), the Flush procedure have to be invoked. The bootloader will fill the page buffer with the content of the flash behind the actual address. This makes sure, the flash gets not changed at the end of the page.\n\nStop Flash\n----------\n\nThe procedure is started by writing the opcode to the Control Point. The bootloader client should execute the procedure, when it suspects that an error occured to reset the bootloader. Timeouts or checksum errors might be reasons to execute this procedure.\n\nRequest Fields     | Length | Value |\n-------------------|-------:|------:|\nOpcode             | 1      | 4     |\n\nThe response is an ATT Notification, with the response code. When the response is received, the\n\nResponse Fields    | Length   | Value   |\n-------------------|---------:|--------:|\nResponse Code      | 1        | 4       |\n\nFlush\n-----\n\nThe procedure is started by writing the opcode to the Control Point. The bootloader must be in flash mode, when executing the procedure and there must be data in the last page buffer that was not automatically flashed (because the last bytes where not at the end of a page). After executing the Flush procedure, the bootloader leaves the flash mode.\n\nRequest Fields     | Length | Value |\n-------------------|-------:|------:|\nOpcode             | 1      | 5     |\n\nThe response is an ATT Notification, with the response code. When the response is received, the\n\nResponse Fields    | Length   | Value                                                                                        |\n-------------------|---------:|---------------------------------------------------------------------------------------------:|\nResponse Code      | 1        | 5                                                                                            |\nChecksum           | 4        | Checksum over Start-Address and all data received since the last Start Flash procedure start |\nConsecutive        | 2        | Consecutive number, that is reseted to 0 with the start of the Start Flash procedure and is incremented after a block became free  |\n\nStart\n-----\n\nThe procedure is started by writing the opcode, followed by the start address to the Control Point.\n\nRequest Fields     | Length | Value |\n-------------------|-------:|------:|\nOpcode             | 1      | 6     |\nStart-Address      | sizeof( std::uint8_t* ) | first byte of the range |\n\nIt is not expected that the bootloader will response with a notification, but instead reset the device and branch to the given address.\n\nReset\n-----\n\nThe procedure is started by writing the opcode to the Control Point.\n\nRequest Fields     | Length | Value |\n-------------------|-------:|------:|\nOpcode             | 1      | 7     |\n\nIt is not expected that the bootloader will response with a notification, but instead reset the device.\n\nRead\n----\n\nThe Read Procedure is started by writing the Start opcode, followed by start and end address of the range to be read, to the Control Point.\n\nRequest Fields     | Length | Value |\n-------------------|-------:|------:|\nOpcode             | 1      | 8     |\nStart-Address      | sizeof( std::uint8_t* ) | address of the range to be read |\nEnd-Address        | sizeof( std::uint8_t* ) | first byte behind the range to be read |\n\nThe Bootloader will send all the requested data in up to MTU - 3 large chunks by indicating them to the Data characteristic. After all data was send, the bootloader response with a notification of the Control Point with a Read response.\n\nResponse Fields    | Length   | Value   |\n-------------------|---------:|--------:|\nResponse Code      | 1        | 8       |\nChecksum           | 4        | Checksum over Start-Address and all data received |\nError Code         | 1        | Reason, why reading from the device failed |\n\nIf reading from the device fails, the bootloader respond by notifying a Read response with an appropriate Error Code field value. An error can be notified every time while the read procedure is running.\n\nData\n====\n\nThere is no layout for the data to be written. Data should be written with an ATT Write Request. The bootloader client have to make sure, that the bootloader can store the send data, by knowing the bootloaders buffer sizes and by observice Progress notifications. The bootloader should try to utillize the connection as much as possible and should send the data in packages that are at most MTU -3 in size.\n\nThe bootloader will response with an ATT Write Response.\n\nThe Bootloader must be in flash mode by executing the Start Flash procedure.\n\nProgress\n========\n\nThe bootloader will send progress notifications to inform the client about buffers that became free.\n\nNotification Fields | Length | Value |\n--------------------|-------:|------:|\nChecksum            | 4      | Checksum over Start-Address and all data received since the last Start Flash procedure start |\nConsecutive         | 2      | Consecutive number, that is reseted to 0 with the start of the Start Flash procedure and is incremented after a block became free  |\nMTU                 | 1      | >= 23   |\n\nThe Consecutive number will overrun with every 65536th freed block. The purpose of the number is to alow the client to align the received values with the blocks send and the checksum that was calculated for that block. The bootloader shall notify a progress PDU when a buffer becomes free. A client can expect that the data of the freed buffer was flashed successfully.\n\nA client that received a progress PDU shall start to send more data.\n\nA client can use the checksum to detect transmission errors, but the client is not required to do so.\n\nIf the data that was send with the write to the Data characteristic (identified by the consecutive number), spans over the end of the current block, the checksum is calculated only till the end of the block.\n\nA client should write the next data to the Data characteristic with a length of MTU -3 at max.\n\n\n"
  },
  {
    "path": "bluetoe/services/csc.hpp",
    "content": "#ifndef BLUETOE_SERVICES_CSC_HPP\n#define BLUETOE_SERVICES_CSC_HPP\n\n#include <bluetoe/service.hpp>\n#include <bluetoe/server.hpp>\n#include <bluetoe/sensor_location.hpp>\n#include <bluetoe/meta_tools.hpp>\n#include <bluetoe/meta_types.hpp>\n\nnamespace bluetoe {\n\n    namespace csc {\n\n        /**\n         * The assigned 16 bit UUID for the Cycling Speed and Cadence service\n         */\n        using service_uuid = service_uuid16< 0x1816 >;\n\n        namespace details {\n            /** @cond HIDDEN_SYMBOLS */\n            struct handler_tag {};\n\n            struct wheel_revolution_data_handler_tag {};\n            struct crank_revolution_data_handler_tag {};\n            /** @endcond */\n        }\n\n        /**\n         * @brief parameter that adds, how the CSC service implementation gets the data needed.\n         *\n         * For further details on the requirement that Handler have to fulfile see cycling_speed_and_cadence_handler_prototype\n         */\n        template < typename Handler >\n        struct handler\n        {\n            /** @cond HIDDEN_SYMBOLS */\n            struct meta_type :\n                details::handler_tag,\n                ::bluetoe::details::valid_service_option_meta_type {};\n\n            typedef Handler user_handler;\n            /** @endcond */\n        };\n\n        /**\n         * @brief Denotes, that the csc service provides wheel revolution data.\n         *\n         * If added to bluetoe::cycling_speed_and_cadence, the user handler have to have the following two functions:\n         * - std::pair< std::uint32_t, std::uint16_t > cumulative_wheel_revolutions_and_time()\n         * - void set_cumulative_wheel_revolutions( std::uint32_t new_value )\n         *\n         * The first is a callback that gives the service the information about the last time, a wheel revolution\n         * value was measured and the coresponding wheel revolution value.\n         * The second function will be called by the service, to set the current wheel revolution value.\n         *\n         * A service must provide wheel_revolution_data_supported, or crank_revolution_data_supported.\n         *\n         * @sa crank_revolution_data_supported\n         * @sa handler\n         * @sa cycling_speed_and_cadence\n         */\n        struct wheel_revolution_data_supported {\n            /** @cond HIDDEN_SYMBOLS */\n            struct meta_type :\n                details::wheel_revolution_data_handler_tag,\n                ::bluetoe::details::valid_service_option_meta_type {};\n\n\n            template < class T >\n            void add_wheel_mesurement( std::uint8_t& flags, std::uint8_t*& out_buffer, T& handler )\n            {\n                flags |= 0x01;\n\n                const std::pair< std::uint32_t, std::uint16_t > revolutions = handler.cumulative_wheel_revolutions_and_time();\n                out_buffer = bluetoe::details::write_32bit( out_buffer, revolutions.first );\n                out_buffer = bluetoe::details::write_16bit( out_buffer, revolutions.second );\n            }\n\n            static constexpr std::uint16_t features = 0x0001;\n            /** @endcond */\n        };\n\n        struct crank_revolution_data_supported {\n            /** @cond HIDDEN_SYMBOLS */\n            struct meta_type :\n                details::crank_revolution_data_handler_tag,\n                ::bluetoe::details::valid_service_option_meta_type {};\n\n            template < class T >\n            void add_crank_mesurement( std::uint8_t& flags, std::uint8_t*& out_buffer, T& handler )\n            {\n                flags |= 0x02;\n\n                const std::pair< std::uint16_t, std::uint16_t > revolutions = handler.cumulative_crank_revolutions_and_time();\n                out_buffer = bluetoe::details::write_16bit( out_buffer, revolutions.first );\n                out_buffer = bluetoe::details::write_16bit( out_buffer, revolutions.second );\n            }\n\n            static constexpr std::uint16_t features = 0x0002;\n            /** @endcond */\n        };\n\n        namespace details {\n            /** @cond HIDDEN_SYMBOLS */\n            static constexpr char service_name[]            = \"Cycling Speed and Cadence\";\n            static constexpr char measurement_name[]        = \"CSC Measurement\";\n            static constexpr char feature_name[]            = \"CSC Feature\";\n            static constexpr char sensor_location_name[]    = \"Sensor Location\";\n            static constexpr char control_point_name[]      = \"SC Control Point\";\n\n            using control_point_uuid = characteristic_uuid16< 0x2A55 >;\n\n            template < typename T >\n            struct service_from_parameters;\n\n            template < typename ... Ts >\n            struct service_from_parameters< std::tuple< Ts... > > {\n                typedef service< Ts... > type;\n            };\n\n            struct no_wheel_revolution_data_supported {\n                typedef details::wheel_revolution_data_handler_tag meta_type;\n\n                template < class T >\n                void add_wheel_mesurement( std::uint8_t&, std::uint8_t*&, T& ) {}\n\n                static constexpr std::uint16_t features = 0;\n            };\n\n            struct no_crank_revolution_data_supported {\n                typedef details::crank_revolution_data_handler_tag meta_type;\n\n                template < class T >\n                void add_crank_mesurement( std::uint8_t&, std::uint8_t*&, T& ) {}\n\n                static constexpr std::uint16_t features = 0;\n            };\n\n            enum {\n                set_cumulative_value_opcode                 = 1,\n                start_sensor_calibration_opcode,\n                update_sensor_location_opcode,\n                request_supported_sensor_locations_opcode,\n                response_code_opcode                        = 16\n            };\n\n            enum {\n                rc_success                  = 1,\n                rc_op_code_not_supported    = 2,\n                rc_invalid_parameter        = 3\n            };\n\n            template < typename SensorLocations >\n            class sensor_position_handler;\n\n            template < typename ... SensorLocations >\n            class sensor_position_handler< std::tuple< SensorLocations... > >\n            {\n            public:\n                sensor_position_handler()\n                    : current_position_( positions_[ 0 ] )\n                    , requested_position_( current_position_ )\n                {\n                }\n\n                std::uint8_t request_supported_sensor_locations_opcode_response( std::size_t read_size, std::uint8_t* out_buffer, std::size_t& out_size )\n                {\n                    static const std::size_t response_size = 3;\n                    assert( read_size >= response_size );\n\n                    out_buffer[ 0 ] = response_code_opcode;\n                    out_buffer[ 1 ] = request_supported_sensor_locations_opcode;\n                    out_buffer[ 2 ] = rc_success;\n\n                    std::size_t max_copy = std::min( read_size - response_size, sizeof ...(SensorLocations) );\n\n                    std::copy( &positions_[ 0 ], &positions_[ max_copy ], &out_buffer[ response_size ] );\n                    out_size = response_size + max_copy;\n\n                    return error_codes::success;\n                }\n\n                std::uint8_t update_sensor_location_opcode_response( std::size_t read_size, std::uint8_t* out_buffer, std::size_t& out_size )\n                {\n                    static_cast< void >( read_size );\n                    static const std::size_t response_size = 3;\n                    assert( read_size >= response_size );\n\n                    out_buffer[ 0 ] = response_code_opcode;\n                    out_buffer[ 1 ] = update_sensor_location_opcode;\n\n                    const auto loc = std::find( std::begin( positions_ ), std::end( positions_ ), requested_position_ );\n\n                    if ( loc != std::end( positions_ ) )\n                    {\n                        out_buffer[ 2 ] = rc_success;\n                        current_position_ = *loc;\n                    }\n                    else\n                    {\n                        out_buffer[ 2 ] = rc_invalid_parameter;\n                    }\n\n                    out_size = response_size;\n\n                    return error_codes::success;\n                }\n\n                void set_sensor_position( std::uint8_t new_sensor_position )\n                {\n                    requested_position_ = new_sensor_position;\n                }\n\n                std::uint8_t csc_sensor_location( std::size_t read_size, std::uint8_t* out_buffer, std::size_t& out_size )\n                {\n                    static_cast< void >( read_size );\n                    assert( read_size > 0 );\n\n                    *out_buffer = current_position_;\n                    out_size    = 1;\n\n                    return error_codes::success;\n                }\n\n\n            private:\n                std::uint8_t current_position_;\n                std::uint8_t requested_position_;\n                static const std::uint8_t positions_[sizeof ...(SensorLocations)];\n            };\n\n            template < typename ... SensorLocations >\n            const std::uint8_t sensor_position_handler< std::tuple< SensorLocations... > >::positions_[sizeof ...(SensorLocations)] = { SensorLocations::value... };\n\n            class no_sensor_position_handler\n            {\n            public:\n                std::uint8_t request_supported_sensor_locations_opcode_response( std::size_t read_size, std::uint8_t* out_buffer, std::size_t& out_size )\n                {\n                    static_cast< void >( read_size );\n                    static const std::size_t response_size = 3;\n                    assert( read_size >= response_size );\n\n                    out_buffer[ 0 ] = response_code_opcode;\n                    out_buffer[ 1 ] = request_supported_sensor_locations_opcode;\n                    out_buffer[ 2 ] = rc_op_code_not_supported;\n                    out_size = response_size;\n\n                    return error_codes::success;\n                }\n\n                std::uint8_t update_sensor_location_opcode_response( std::size_t read_size, std::uint8_t* out_buffer, std::size_t& out_size )\n                {\n                    static_cast< void >( read_size );\n                    static const std::size_t response_size = 3;\n                    assert( read_size >= response_size );\n\n                    out_buffer[ 0 ] = response_code_opcode;\n                    out_buffer[ 1 ] = update_sensor_location_opcode;\n                    out_buffer[ 2 ] = rc_op_code_not_supported;\n                    out_size = response_size;\n\n                    return error_codes::success;\n                }\n\n                void set_sensor_position( std::uint8_t ) {}\n            };\n\n            template < class SensorPositionHandler >\n            class control_point_handler : public SensorPositionHandler\n            {\n            public:\n                control_point_handler()\n                    : procedure_in_progress_( false )\n                {\n                }\n\n                std::uint8_t csc_read_control_point( std::size_t read_size, std::uint8_t* out_buffer, std::size_t& out_size )\n                {\n                    procedure_in_progress_  = false;\n\n                    switch ( current_opcode_ )\n                    {\n                    case set_cumulative_value_opcode:\n                        {\n                            static const std::size_t response_size = 3;\n                            assert( read_size >= response_size );\n\n                            out_buffer[ 0 ] = response_code_opcode;\n                            out_buffer[ 1 ] = set_cumulative_value_opcode;\n                            out_buffer[ 2 ] = rc_success;\n\n                            out_size = response_size;\n                        }\n                        break;\n                    case request_supported_sensor_locations_opcode:\n                        {\n                            return this->request_supported_sensor_locations_opcode_response( read_size, out_buffer, out_size );\n                        }\n                        break;\n                    case update_sensor_location_opcode:\n                        {\n                            return this->update_sensor_location_opcode_response( read_size, out_buffer, out_size );\n                        }\n                        break;\n                    default:\n                        {\n                            static const std::size_t response_size = 3;\n                            assert( read_size >= response_size );\n\n                            out_buffer[ 0 ] = response_code_opcode;\n                            out_buffer[ 1 ] = current_opcode_;\n                            out_buffer[ 2 ] = rc_op_code_not_supported;\n\n                            out_size = response_size;\n                        }\n                    }\n\n                    return error_codes::success;\n                }\n\n                template < class Handler >\n                std::pair< std::uint8_t, bool > csc_write_control_point( std::size_t write_size, const std::uint8_t* value, Handler& handler )\n                {\n                    if ( write_size < 1 )\n                        return std::make_pair( error_codes::invalid_handle, false );\n\n                    if ( procedure_in_progress_ )\n                        return std::make_pair( error_codes::procedure_already_in_progress, false );\n\n                    procedure_in_progress_  = true;\n                    current_opcode_         = *value;\n                    ++value;\n\n                    switch ( current_opcode_ )\n                    {\n                    case set_cumulative_value_opcode:\n                        {\n                            if ( write_size != 1 + 4 )\n                                return std::make_pair( error_codes::invalid_pdu, false );\n\n                            handler.set_cumulative_wheel_revolutions( bluetoe::details::read_32bit( value ) );\n                            return std::make_pair( error_codes::success, false );\n                        }\n                    case request_supported_sensor_locations_opcode:\n                        {\n                            if ( write_size != 1 )\n                                return std::make_pair( error_codes::invalid_pdu, false );\n\n                            return std::make_pair( error_codes::success, true );\n                        }\n                    case update_sensor_location_opcode:\n                        {\n                            if ( write_size != 1 + 1 )\n                                return std::make_pair( error_codes::invalid_pdu, false );\n\n                            this->set_sensor_position( *value);\n\n                            return std::make_pair( error_codes::success, true );\n                        }\n                    default:\n                        // according to the spec with have to response with success and then indicate an error\n                        return std::make_pair( error_codes::success, true );\n                    }\n\n                }\n            private:\n                std::uint8_t current_opcode_;\n                bool         procedure_in_progress_;\n            };\n\n            struct no_control_point_handler {\n                std::uint8_t csc_read_control_point( std::size_t, std::uint8_t*, std::size_t& ) {\n                    return 0;\n                }\n\n                template < class Handler >\n                std::pair< std::uint8_t, bool > csc_write_control_point( std::size_t, const std::uint8_t*, Handler& ) {\n                    return std::make_pair( 0, false );\n                }\n            };\n\n            template < typename Base, typename WheelHandler, typename CrankHandler, typename ControlPointHandler >\n            class implementation : public Base, WheelHandler, CrankHandler, public ControlPointHandler\n            {\n            public:\n                static constexpr std::size_t max_response_size = 1 + 4 + 2 + 2 + 2;\n\n                void csc_wheel_revolution( std::uint32_t, std::uint32_t )\n                {\n                }\n\n                std::uint8_t csc_mesurement( std::size_t read_size, std::uint8_t* out_buffer, std::size_t& out_size )\n                {\n                    static_cast< void >( read_size );\n                    assert( read_size >= max_response_size );\n\n                    std::uint8_t* out_ptr = out_buffer + 1;\n\n                    *out_buffer = 0;\n                    this->add_wheel_mesurement( *out_buffer, out_ptr, *this );\n                    this->add_crank_mesurement( *out_buffer, out_ptr, *this );\n\n                    out_size = out_ptr - out_buffer;\n\n                    return error_codes::success;;\n                }\n\n                std::uint8_t csc_read_control_point( std::size_t read_size, std::uint8_t* out_buffer, std::size_t& out_size )\n                {\n                    return ControlPointHandler::csc_read_control_point( read_size, out_buffer, out_size );\n                }\n\n                std::pair< std::uint8_t, bool > csc_write_control_point( std::size_t write_size, const std::uint8_t* value )\n                {\n                    return ControlPointHandler::csc_write_control_point( write_size, value, *this );\n                }\n\n                template < class Server >\n                void notify_timed_update( Server& server )\n                {\n                    server.template notify< characteristic_uuid16< 0x2A5B > >();\n                }\n\n                template < class Server >\n                void confirm_cumulative_wheel_revolutions( Server& server )\n                {\n                    server.template indicate< control_point_uuid >();\n                }\n            private:\n            };\n\n            template < bool HasSensorlocation, bool HasMultipleSensorlocations, typename SensorList >\n            struct select_sensorlocation_implementation;\n\n            template < typename SensorList >\n            struct select_sensorlocation_implementation< false, false, SensorList >\n            {\n                using type = std::tuple<>;\n            };\n\n            template < typename SensorPosition >\n            struct select_sensorlocation_implementation< true, false, std::tuple< SensorPosition > >\n            {\n                using type = characteristic<\n                    characteristic_uuid16< 0x2A5D >,\n                    characteristic_name< sensor_location_name >,\n                    fixed_uint8_value< SensorPosition::value >\n                >;\n            };\n\n            template < typename SensorList >\n            struct select_sensorlocation_implementation< true, true, SensorList >\n            {\n                using type = characteristic<\n                    characteristic_uuid16< 0x2A5D >,\n                    characteristic_name< sensor_location_name >,\n                    bluetoe::mixin_read_handler<\n                        sensor_position_handler< SensorList >,\n                        &sensor_position_handler< SensorList >::csc_sensor_location\n                    >\n                >;\n            };\n\n            template < typename ... Options >\n            struct calculate_service\n            {\n                using sensor_locations = typename bluetoe::details::find_all_by_meta_type<\n                    bluetoe::details::sensor_location_meta_type, Options... >::type;\n\n                using wheel_handler    = typename bluetoe::details::find_by_meta_type< wheel_revolution_data_handler_tag, Options..., no_wheel_revolution_data_supported >::type;\n                using crank_handler    = typename bluetoe::details::find_by_meta_type< crank_revolution_data_handler_tag, Options..., no_crank_revolution_data_supported >::type;\n\n                static_assert( !std::is_same< wheel_handler, bluetoe::details::no_such_type >::value, \"\" );\n                static_assert( !std::is_same< crank_handler, bluetoe::details::no_such_type >::value, \"\" );\n\n                using service_handler = typename bluetoe::details::find_by_meta_type< handler_tag, Options ... >::type;\n\n                static_assert( !std::is_same< service_handler, bluetoe::details::no_such_type >::value,\n                    \"You need to provide a bluetoe::crc::handler<> to define how the protocol can access the messured values.\" );\n\n\n                static constexpr bool has_static_sensorlocation   = std::tuple_size< sensor_locations >::value == 1u;\n                static constexpr bool has_multiple_sensorlocation = std::tuple_size< sensor_locations >::value > 1u;\n                static constexpr bool has_sensorlocation          = has_static_sensorlocation || has_multiple_sensorlocation;\n\n                static constexpr bool has_set_cumulative_value    = wheel_handler::features != 0;\n                static constexpr bool has_control_point           = has_set_cumulative_value | has_multiple_sensorlocation;\n\n                using service_implementation = implementation<\n                    typename service_handler::user_handler, wheel_handler, crank_handler,\n                    typename bluetoe::details::select_type<\n                        has_control_point,\n                        typename bluetoe::details::select_type<\n                            has_multiple_sensorlocation,\n                            control_point_handler< sensor_position_handler< sensor_locations > >,\n                            control_point_handler< no_sensor_position_handler >\n                        >::type,\n                        no_control_point_handler\n                    >::type\n                >;\n\n                using mandatory_characteristics = std::tuple<\n                    characteristic<\n                        characteristic_uuid16< 0x2A5B >,\n                        characteristic_name< measurement_name >,\n                        bluetoe::no_read_access,\n                        bluetoe::no_write_access,\n                        bluetoe::notify,\n                        bluetoe::mixin_read_handler< service_implementation, &service_implementation::csc_mesurement >\n                    >,\n                    characteristic<\n                        characteristic_uuid16< 0x2A5C >,\n                        characteristic_name< feature_name >,\n                        fixed_uint16_value< wheel_handler::features | crank_handler::features >\n                    >\n                >;\n\n                using characteristics_with_sensorlocation = typename bluetoe::details::add_type<\n                    mandatory_characteristics,\n                    typename select_sensorlocation_implementation<\n                        has_sensorlocation,\n                        has_multiple_sensorlocation,\n                        sensor_locations\n                    >::type\n                >::type;\n\n                using characteristics_with_control_point =\n                    typename bluetoe::details::select_type<\n                        has_control_point,\n                        typename bluetoe::details::add_type<\n                            characteristics_with_sensorlocation,\n                            characteristic<\n                                control_point_uuid,\n                                characteristic_name< control_point_name >,\n                                bluetoe::no_read_access,\n                                bluetoe::indicate,\n                                bluetoe::mixin_write_indication_control_point_handler< service_implementation, &service_implementation::csc_write_control_point, control_point_uuid >,\n                                bluetoe::mixin_read_handler< service_implementation, &service_implementation::csc_read_control_point >\n                            >\n                        >::type,\n                        characteristics_with_sensorlocation\n                    >::type;\n\n                using all_characteristics = characteristics_with_control_point;\n\n                using default_parameter = std::tuple<\n                    mixin< service_implementation >,\n                    service_uuid,\n                    bluetoe::service_name< service_name >,\n                    Options... >;\n\n                typedef typename service_from_parameters<\n                    typename bluetoe::details::add_type< default_parameter, all_characteristics >::type\n                 >::type type;\n            };\n            /** @endcond */\n        }\n    }\n\n    /**\n     * @typedef cycling_speed_and_cadence\n     *\n     * Implementation of the Cycling Speed and Cadence Service (CSCS) 1.0\n     *\n     * @sa bluetoe::csc::wheel_revolution_data_supported\n     * @sa bluetoe::csc::crank_revolution_data_supported\n     * @sa bluetoe::csc::handler\n     */\n    template < typename ... Options >\n    using cycling_speed_and_cadence = typename csc::details::calculate_service< Options... >::type;\n\n    /**\n     * @brief Prototype for an interface type\n     */\n    class cycling_speed_and_cadence_handler_prototype\n    {\n    public:\n        /**\n         * Either this function must be provided, or cumulative_crank_revolutions(), or both.\n         *\n         * The function have to return the Cumulative Wheel Revolutions (first) and the\n         * Last Wheel Event Time (in 1/1024s).\n         *\n         * Add csc::wheel_revolution_data_supported to cycling_speed_and_cadence to indicate support for wheel revolutions.\n         *\n         * @sa csc::wheel_revolution_data_supported\n         * @sa cycling_speed_and_cadence\n         */\n        std::pair< std::uint32_t, std::uint16_t > cumulative_wheel_revolutions_and_time();\n\n        /**\n         * Either this function must be provided, or cumulative_wheel_revolutions(), or both.\n         *\n         * The function have to return the Cumulative Crank Revolutions (first) and the\n         * Last Wheel Event Time (in 1/1024s)\n         *\n         * Add csc::crank_revolution_data_supported to cycling_speed_and_cadence to indicate support for crank revolutions.\n         *\n         * @sa csc::crank_revolution_data_supported\n         * @sa cycling_speed_and_cadence\n         */\n        std::pair< std::uint16_t, std::uint16_t > cumulative_crank_revolutions_and_time();\n\n        /**\n         * Function will be called, when the cumlative wheel revolution have to be changed.\n         *\n         * The update of the value have to be confirmed by calling confirm_cumulative_wheel_revolutions().\n         * Calling confirm_cumulative_wheel_revolutions() can be done synchronous, or asynchroiunous.\n         * It's save to call confirm_cumulative_wheel_revolutions() from an ISR.\n         */\n        void set_cumulative_wheel_revolutions( std::uint32_t new_value );\n\n    };\n}\n\n#endif // include guard\n"
  },
  {
    "path": "bluetoe/services/dis.hpp",
    "content": "#ifndef BLUETOE_SERVICES_DIS_HPP\n#define BLUETOE_SERVICES_DIS_HPP\n\n#include <bluetoe/service.hpp>\n#include <bluetoe/characteristic.hpp>\n\nnamespace bluetoe {\n\n    namespace dis {\n\n        /**\n         * The assigned 16 bit UUID for the Device Information Service\n         */\n        using service_uuid = service_uuid16< 0x180A >;\n\n        using manufacturer_name_uuid    = characteristic_uuid16< 0x2A29 >;\n        using model_number_uuid         = characteristic_uuid16< 0x2A24 >;\n        using serial_number_uuid        = characteristic_uuid16< 0x2A25 >;\n        using hardware_revision_uuid    = characteristic_uuid16< 0x2A27 >;\n        using firmware_revision_uuid    = characteristic_uuid16< 0x2A26 >;\n        using software_revision_uuid    = characteristic_uuid16< 0x2A28 >;\n        using system_uuid               = characteristic_uuid16< 0x2A23 >;\n        using ieee_11073_20601_regulatory_certification_data_list_uuid = characteristic_uuid16< 0x2A2A >;\n        using pnp_uuid                  = characteristic_uuid16< 0x2A50 >;\n\n        /**\n         * @brief includes a Manufacturer Name String characteristic into the Device Information Service.\n         */\n        template < const char* Manufacturer >\n        using manufacturer_name =\n            bluetoe::characteristic<\n                bluetoe::cstring_value< Manufacturer >,\n                manufacturer_name_uuid\n            >\n        ;\n\n        /**\n         * @brief includes a Model Number String characteristic into the Device Information Service.\n         */\n        template < const char* ModelNumberString >\n        using model_number =\n            bluetoe::characteristic<\n                bluetoe::cstring_value< ModelNumberString >,\n                model_number_uuid\n            >\n        ;\n\n        /**\n         * @brief includes a Serial Number String characteristic into the Device Information Service.\n         */\n        template < const char* SerialNumberString >\n        using serial_number =\n            bluetoe::characteristic<\n                bluetoe::cstring_value< SerialNumberString >,\n                serial_number_uuid\n            >\n        ;\n\n        /**\n         * @brief includes a Hardware Revision String characteristic into the Device Information Service.\n         */\n        template < const char* HardwareRevisionString >\n        using hardware_revision =\n            bluetoe::characteristic<\n                bluetoe::cstring_value< HardwareRevisionString >,\n                hardware_revision_uuid\n            >\n        ;\n\n        /**\n         * @brief includes a Firmware Revision String characteristic into the Device Information Service.\n         */\n        template < const char* FirmwareRevisionString >\n        using firmware_revision =\n            bluetoe::characteristic<\n                bluetoe::cstring_value< FirmwareRevisionString >,\n                firmware_revision_uuid\n            >\n        ;\n\n        /**\n         * @brief includes a Software Revision String characteristic into the Device Information Service.\n         */\n        template < const char* SoftwareRevisionString >\n        using software_revision =\n            bluetoe::characteristic<\n                bluetoe::cstring_value< SoftwareRevisionString >,\n                software_revision_uuid\n            >\n        ;\n\n        /**\n         * @todo not implemented\n         */\n        template < std::uint64_t ManufacturerIdentifier, std::uint32_t OrganizationallyUniqueIdentifier >\n        struct system_id\n        {\n        };\n\n        /**\n         * @todo not implemeted\n         */\n        template < typename Value >\n        struct ieee_11073_20601_regulatory_certification_data_list\n        {\n        };\n\n        /**\n         * @brief enumeration that defines, the valid domain of a used vendor ID\n         */\n        enum class vendor_id_source_t : std::uint8_t\n        {\n            /**\n             * Bluetooth SIG assigned Company Identifier value from the Assigned Numbers document\n             */\n            bluetooth   = 1,\n\n            /**\n             * USB Implementer’s Forum assigned Vendor ID value\n             */\n            usb         = 2\n        };\n\n        namespace details {\n            /** @cond HIDDEN_SYMBOLS */\n            template < vendor_id_source_t VendorIDSource, std::uint16_t VendorID, std::uint16_t ProductID, std::uint16_t ProductVersion >\n            struct pnp_id_value : bluetoe::cstring_wrapper< pnp_id_value< VendorIDSource, VendorID, ProductID, ProductVersion > >\n            {\n                static constexpr std::size_t data_size = 7u;\n\n                static constexpr std::uint8_t data[ data_size ] = {\n                    static_cast< std::uint8_t >( VendorIDSource ),\n                    static_cast< std::uint8_t >( VendorID & 0xff ),\n                    static_cast< std::uint8_t >( VendorID >> 8 ),\n                    static_cast< std::uint8_t >( ProductID & 0xff ),\n                    static_cast< std::uint8_t >( ProductID >> 8 ),\n                    static_cast< std::uint8_t >( ProductVersion & 0xff),\n                    static_cast< std::uint8_t >( ProductVersion >> 8 )\n                };\n\n                static constexpr std::uint8_t const * value()\n                {\n\n                    static_assert( data_size == sizeof data, \"\" );\n\n                    return data;\n                }\n\n                static constexpr std::size_t size()\n                {\n                    return data_size;\n                }\n            };\n\n            template < vendor_id_source_t VendorIDSource, std::uint16_t VendorID, std::uint16_t ProductID, std::uint16_t ProductVersion >\n            constexpr std::uint8_t pnp_id_value< VendorIDSource, VendorID, ProductID, ProductVersion >::data[ data_size ];\n            /** @endcond */\n        }\n\n        /**\n         * @brief includes a PnP ID characteristic\n         */\n        template < vendor_id_source_t VendorIDSource, std::uint16_t VendorID, std::uint16_t ProductID, std::uint16_t ProductVersion >\n        using pnp_id =\n            bluetoe::characteristic<\n                details::pnp_id_value< VendorIDSource, VendorID, ProductID, ProductVersion >,\n                pnp_uuid\n            >\n        ;\n    }\n\n    /**\n     * @brief implementation of a Device Information Service (DIS) 1.1\n     *\n     * @sa dis::manufacturer_name\n     * @sa dis::model_number\n     * @sa dis::serial_number\n     * @sa dis::hardware_revision\n     * @sa dis::firmware_revision\n     * @sa dis::software_revision\n     * @sa dis::system_id\n     * @sa dis::ieee_11073_20601_regulatory_certification_data_list\n     * @sa dis::pnp_id\n     */\n    template < typename ... Options >\n    using device_information_service = bluetoe::service<\n        dis::service_uuid,\n        Options...\n    >;\n}\n\n#endif\n"
  },
  {
    "path": "bluetoe/services/gatt.hpp",
    "content": "#ifndef BLUETOE_SERVICES_GATT_HPP\n#define BLUETOE_SERVICES_GATT_HPP\n\n#include <bluetoe/service.hpp>\n#include <bluetoe/characteristic.hpp>\n#include <bluetoe/attribute_handle.hpp>\n\nnamespace bluetoe {\n\n    namespace gatt {\n        /**\n         * @brief The assigned 16 bit UUID for the Generic Attribute Profile service\n         */\n        using service_uuid = service_uuid16< 0x1801 >;\n\n        /**\n         * @brief The assigned 16 bit UUID for Service Changed characteristic\n         */\n        using service_changed_uuid = characteristic_uuid16< 0x2A05 >;\n\n        /**\n         * @brief Service Changed characteristic\n         */\n        using service_changed_characteristic = characteristic<\n            service_changed_uuid,\n            indicate,\n            fixed_uint32_value< 0xFFFF0001 >\n        >;\n\n        /**\n         * @brief Generic Attribute Profile service with a single Service Changed characteristic\n         *\n         * As the handle of the Service Changed Value Attribute handle should be stable, equal\n         * over all future versions of your server, this service should always be the first\n         * service in the server. If that is not possible, use service_with_fixed_handles<> and\n         * assign the attribute handles manually.\n         */\n        using service = ::bluetoe::service<\n            service_uuid,\n            service_changed_characteristic\n        >;\n\n        /**\n         * @brief Generic Attribute Profile service with a single Service Changed characteristic\n         *\n         * This version allows manually allocating the attribute handles.\n         */\n        template <\n            std::uint16_t ServiceHandle,\n            std::uint16_t ServiceChangedCharDeclarationHandle = ServiceHandle + 1,\n            std::uint16_t ServiceChangedCharValueHandle       = ServiceHandle + 2,\n            std::uint16_t ServiceChangedCahrCCCDHandle        = ServiceHandle + 3 >\n        using service_with_fixed_handles = ::bluetoe::service<\n            attribute_handle< ServiceHandle >,\n            service_uuid,\n            characteristic<\n                attribute_handles<\n                    ServiceChangedCharDeclarationHandle,\n                    ServiceChangedCharValueHandle,\n                    ServiceChangedCahrCCCDHandle >,\n                service_changed_uuid,\n                indicate,\n                fixed_uint32_value< 0xFFFF0001 >\n            >\n        >;\n    }\n}\n\n#endif\n\n"
  },
  {
    "path": "bluetoe/services/hid.hpp",
    "content": "#ifndef BLUETOE_SERVICES_HID_HPP\n#define BLUETOE_SERVICES_HID_HPP\n\n#include <bluetoe/service.hpp>\n#include <bluetoe/characteristic.hpp>\n\nnamespace bluetoe {\n\n    namespace hid {\n        /**\n         * The assigned 16 bit UUID for the Human Interface Device\n         */\n        using service_uuid = service_uuid16< 0x1812 >;\n\n        using protocol_mode_uuid                = characteristic_uuid16< 0x2A4E >;\n        using report_uuid                       = characteristic_uuid16< 0x2A4D >;\n        using report_map_uuid                   = characteristic_uuid16< 0x2A4B >;\n        using boot_keyboard_input_report_uuid   = characteristic_uuid16< 0x2A22 >;\n        using boot_keyboard_output_report_uuid  = characteristic_uuid16< 0x2A32 >;\n        using boot_mouse_input_report_uuid      = characteristic_uuid16< 0x2A33 >;\n        using hid_information_uuid              = characteristic_uuid16< 0x2A4A >;\n        using hid_control_point_uuid            = characteristic_uuid16< 0x2A4C >;\n\n        static constexpr std::uint16_t report_reference_descriptor_uuid = 0x2908;\n\n        enum class report_type : std::uint8_t {\n            input = 1,\n            output = 2,\n            feature = 3\n        };\n\n        namespace details {\n            template < std::uint8_t ReportID, report_type Type >\n            struct report_reference_impl {\n                static const std::uint8_t data[ 2 ];\n\n                using descriptor = bluetoe::descriptor< report_reference_descriptor_uuid, data, sizeof( data ) >;\n            };\n\n            template < std::uint8_t ReportID, report_type Type >\n            const std::uint8_t report_reference_impl< ReportID, Type >::data[ 2 ] = { ReportID, static_cast< std::uint8_t >( Type ) };\n\n        }\n\n        /**\n         * @brief an Input Report Reference Descriptor\n         */\n        template < std::uint8_t ReportID >\n        using input_report_reference = typename details::report_reference_impl< ReportID, report_type::input >::descriptor;\n\n        /**\n         * @brief an Output Report Reference Descriptor\n         */\n        template < std::uint8_t ReportID >\n        using output_report_reference = typename details::report_reference_impl< ReportID, report_type::output >::descriptor;\n\n        /**\n         * @brief a Feature Report Reference Descriptor\n         */\n        template < std::uint8_t ReportID >\n        using feature_report_reference = typename details::report_reference_impl< ReportID, report_type::feature >::descriptor;\n    }\n}\n\n#endif\n"
  },
  {
    "path": "bluetoe/sm/CMakeLists.txt",
    "content": "add_library(bluetoe_security_manager INTERFACE)\nadd_library(bluetoe::sm ALIAS bluetoe_security_manager)\n\ntarget_include_directories(bluetoe_security_manager INTERFACE include)\n"
  },
  {
    "path": "bluetoe/sm/include/bluetoe/io_capabilities.hpp",
    "content": "#ifndef BLUETOE_SM_INCLUDE_IO_CAPABILTIES_HPP\n#define BLUETOE_SM_INCLUDE_IO_CAPABILTIES_HPP\n\n#include <bluetoe/meta_tools.hpp>\n#include <bluetoe/ll_meta_types.hpp>\n#include <bluetoe/bits.hpp>\n\nnamespace bluetoe\n{\n    namespace details {\n        struct pairing_input_capabilty_meta_type {};\n        struct pairing_output_capabilty_meta_type {};\n        struct pairing_just_works_meta_type {};\n\n        enum class io_capabilities : std::uint8_t {\n            display_only            = 0x00,\n            display_yes_no          = 0x01,\n            keyboard_only           = 0x02,\n            no_input_no_output      = 0x03,\n            keyboard_display        = 0x04,\n            last = keyboard_display\n        };\n\n        enum class legacy_pairing_algorithm : std::uint8_t {\n            just_works,\n            oob_authentication,\n            passkey_entry_display,\n            passkey_entry_input\n        };\n\n        enum class lesc_pairing_algorithm : std::uint8_t {\n            just_works,\n            oob_authentication,\n            passkey_entry_display,\n            passkey_entry_input,\n            numeric_comparison\n        };\n\n    }\n\n    /**\n     * @brief defines that the device has no way to receive input from the user during pairing\n     *\n     * This is the default, if no other pairing input capability is given.\n     *\n     * @sa pairing_yes_no\n     * @sa pairing_keyboard\n     */\n    struct pairing_no_input\n    {\n        /** @cond HIDDEN_SYMBOLS */\n        static std::array< std::uint8_t, 16 > sm_pairing_passkey()\n        {\n            return {{0}};\n        }\n\n        template < class S >\n        static bool sm_pairing_request_yes_no( const S& )\n        {\n            return true;\n        }\n\n        struct meta_type :\n            details::pairing_input_capabilty_meta_type,\n            link_layer::details::valid_link_layer_option_meta_type {};\n        /** @endcond */\n    };\n\n    /**\n     * @brief interface that can be stored to provide response to a yes_no question\n     *        asynchronously.\n     *\n     * @sa pairing_yes_no\n     */\n    class pairing_yes_no_response\n    {\n    public:\n        /** @cond HIDDEN_SYMBOLS */\n        virtual void yes_no_response( bool ) = 0;\n        /** @endcond */\n    protected:\n        ~pairing_yes_no_response() = default;\n    };\n\n    /**\n     * @brief Device has at least two buttons that can be easily mapped to 'yes'\n     *        and 'no' or the device has a mechanism whereby the user can\n     *        indicate either 'yes' or 'no'.\n     *\n     * The parameter T have to be a class type with following none static member\n     * function:\n     *\n     * void sm_pairing_yes_no( pairing_yes_no_response& response );\n     *\n     * The passed response parameter can be stored to respond later to the question or the yes_no_response()\n     * function of the response can be called directly.\n     *\n     * @sa pairing_keyboard\n     * @sa pairing_no_input\n     */\n    template < typename T, T& Obj >\n    struct pairing_yes_no\n    {\n        /** @cond HIDDEN_SYMBOLS */\n        static std::array< std::uint8_t, 16 > sm_pairing_passkey()\n        {\n            return {{0}};\n        }\n\n        template < class S >\n        static void sm_pairing_request_yes_no( S& state )\n        {\n            state.wait_for_user_response();\n            Obj.sm_pairing_yes_no( state );\n        }\n\n        struct meta_type :\n            details::pairing_input_capabilty_meta_type,\n            link_layer::details::valid_link_layer_option_meta_type {};\n        /** @endcond */\n    };\n\n    /**\n     * @brief Device has a numeric keyboard that can input the numbers '0' to '9' and a confirmation.\n     *\n     * Device also has at least two buttons that can be easily mapped to 'yes' and 'no' or the device\n     * has a mechanism whereby the user can indicate either 'yes' or 'no'.\n     *\n     * The parameter T have to be a class type with following none static member\n     * functions:\n     *\n     * int sm_pairing_passkey();\n     * bool sm_pairing_yes_no();\n     *\n     * @sa pairing_yes_no\n     * @sa pairing_no_input\n     */\n    template < typename T, T& Obj >\n    struct pairing_keyboard\n    {\n        /** @cond HIDDEN_SYMBOLS */\n        static std::array< std::uint8_t, 16 > sm_pairing_passkey()\n        {\n            std::array< std::uint8_t, 16 > result = {{ 0 }};\n            details::write_32bit( result.data(), Obj.sm_pairing_passkey() );\n\n            return result;\n        }\n\n        struct meta_type :\n            details::pairing_input_capabilty_meta_type,\n            link_layer::details::valid_link_layer_option_meta_type {};\n        /** @endcond */\n    };\n\n    /**\n     * @brief defines that the device has no means to output a numeric value\n     */\n    struct pairing_no_output\n    {\n        /** @cond HIDDEN_SYMBOLS */\n        static details::io_capabilities get_io_capabilities( const pairing_no_input& )\n        {\n            return details::io_capabilities::no_input_no_output;\n        }\n\n        template < typename T, T& Obj >\n        static details::io_capabilities get_io_capabilities( const pairing_yes_no< T, Obj >& )\n        {\n            return details::io_capabilities::no_input_no_output;\n        }\n\n        template < typename T, T& Obj >\n        static details::io_capabilities get_io_capabilities( const pairing_keyboard< T, Obj >& )\n        {\n            return details::io_capabilities::keyboard_only;\n        }\n\n        static details::legacy_pairing_algorithm select_legacy_pairing_algorithm( const pairing_no_input&, details::io_capabilities /* io_capability */ )\n        {\n            return details::legacy_pairing_algorithm::just_works;\n        }\n\n        template < typename T, T& Obj >\n        static details::legacy_pairing_algorithm select_legacy_pairing_algorithm( const pairing_yes_no< T, Obj >&, details::io_capabilities /* io_capability */ )\n        {\n            return details::legacy_pairing_algorithm::just_works;\n        }\n\n        template < typename T, T& Obj >\n        static details::legacy_pairing_algorithm select_legacy_pairing_algorithm( const pairing_keyboard< T, Obj >&, details::io_capabilities io_capability )\n        {\n            if ( io_capability == details::io_capabilities::no_input_no_output )\n                return details::legacy_pairing_algorithm::just_works;\n\n            return details::legacy_pairing_algorithm::passkey_entry_input;\n        }\n\n        static details::lesc_pairing_algorithm select_lesc_pairing_algorithm( const pairing_no_input&, details::io_capabilities )\n        {\n            return details::lesc_pairing_algorithm::just_works;\n        }\n\n        template < typename T, T& Obj >\n        static details::lesc_pairing_algorithm select_lesc_pairing_algorithm( const pairing_yes_no< T, Obj >&, details::io_capabilities )\n        {\n            return details::lesc_pairing_algorithm::just_works;\n        }\n\n        template < typename T, T& Obj >\n        static details::lesc_pairing_algorithm select_lesc_pairing_algorithm( const pairing_keyboard< T, Obj >&, details::io_capabilities io_capability )\n        {\n            if ( io_capability == details::io_capabilities::no_input_no_output )\n                return details::lesc_pairing_algorithm::just_works;\n\n            return details::lesc_pairing_algorithm::passkey_entry_input;\n        }\n\n        static void sm_pairing_numeric_output( const std::array< std::uint8_t, 16 >& )\n        {\n        }\n\n        template < class S, class F >\n        static void sm_pairing_numeric_compare_output( const S&, F& )\n        {\n        }\n\n        struct meta_type :\n            details::pairing_output_capabilty_meta_type,\n            link_layer::details::valid_link_layer_option_meta_type {};\n        /** @endcond */\n    };\n\n    /**\n     * @brief the device has a mean to output the 6 digit pass key used during\n     *        the pairing process.\n     *\n     * The parameter T have to be a class type with following none static member\n     * function:\n     *\n     * void sm_pairing_numeric_output( int pass_key );\n     *\n     * @sa pairing_no_output\n     */\n    template < typename T, T& Obj >\n    struct pairing_numeric_output\n    {\n        /** @cond HIDDEN_SYMBOLS */\n        static details::io_capabilities get_io_capabilities( const pairing_no_input& )\n        {\n            return details::io_capabilities::display_only;\n        }\n\n        template < typename O, O& Other >\n        static details::io_capabilities get_io_capabilities( const pairing_yes_no< O, Other >& )\n        {\n            return details::io_capabilities::display_yes_no;\n        }\n\n        template < typename O, O& Other >\n        static details::io_capabilities get_io_capabilities( const pairing_keyboard< O, Other >& )\n        {\n            return details::io_capabilities::keyboard_display;\n        }\n\n        static details::legacy_pairing_algorithm select_legacy_pairing_algorithm( const pairing_no_input&, details::io_capabilities io_capability )\n        {\n            if ( io_capability == details::io_capabilities::keyboard_only || io_capability == details::io_capabilities::keyboard_display )\n                return details::legacy_pairing_algorithm::passkey_entry_display;\n\n            return details::legacy_pairing_algorithm::just_works;\n        }\n\n        template < typename O, O& Other >\n        static details::legacy_pairing_algorithm select_legacy_pairing_algorithm( const pairing_yes_no< O, Other >&, details::io_capabilities io_capability )\n        {\n            if ( io_capability == details::io_capabilities::keyboard_only || io_capability == details::io_capabilities::keyboard_display )\n                return details::legacy_pairing_algorithm::passkey_entry_display;\n\n            return details::legacy_pairing_algorithm::just_works;\n        }\n\n        template < typename O, O& Other >\n        static details::legacy_pairing_algorithm select_legacy_pairing_algorithm( const pairing_keyboard< O, Other >&, details::io_capabilities io_capability )\n        {\n            if ( io_capability == details::io_capabilities::no_input_no_output )\n                return details::legacy_pairing_algorithm::just_works;\n\n            if ( io_capability == details::io_capabilities::keyboard_only )\n                return details::legacy_pairing_algorithm::passkey_entry_display;\n\n            return details::legacy_pairing_algorithm::passkey_entry_input;\n        }\n\n        static details::lesc_pairing_algorithm select_lesc_pairing_algorithm( const pairing_no_input&, details::io_capabilities io_capability )\n        {\n            if ( io_capability == details::io_capabilities::keyboard_only || io_capability == details::io_capabilities::keyboard_display )\n                return details::lesc_pairing_algorithm::passkey_entry_display;\n\n            return details::lesc_pairing_algorithm::just_works;\n        }\n\n        template < typename O, O& Other >\n        static details::lesc_pairing_algorithm select_lesc_pairing_algorithm( const pairing_yes_no< O, Other >&, details::io_capabilities io_capability )\n        {\n            if ( io_capability == details::io_capabilities::display_yes_no || io_capability == details::io_capabilities::keyboard_display )\n                return details::lesc_pairing_algorithm::numeric_comparison;\n\n            if ( io_capability == details::io_capabilities::keyboard_only )\n                return details::lesc_pairing_algorithm::passkey_entry_display;\n\n            return details::lesc_pairing_algorithm::just_works;\n        }\n\n        template < typename O, O& Other >\n        static details::lesc_pairing_algorithm select_lesc_pairing_algorithm( const pairing_keyboard< O, Other >&, details::io_capabilities io_capability )\n        {\n            if ( io_capability == details::io_capabilities::display_yes_no || io_capability == details::io_capabilities::keyboard_display )\n                return details::lesc_pairing_algorithm::numeric_comparison;\n\n            if ( io_capability == details::io_capabilities::display_only )\n                return details::lesc_pairing_algorithm::passkey_entry_input;\n\n            if ( io_capability == details::io_capabilities::keyboard_only )\n                return details::lesc_pairing_algorithm::passkey_entry_display;\n\n            return details::lesc_pairing_algorithm::just_works;\n        }\n\n        static void sm_pairing_numeric_output( const std::array< std::uint8_t, 16 >& key )\n        {\n            Obj.sm_pairing_numeric_output( static_cast< int >( details::read_32bit( key.data() ) ) );\n        }\n\n        template < class S, class F >\n        static void sm_pairing_numeric_compare_output( const S& state, F& funcs )\n        {\n            const auto& Na = state.remote_nonce();\n            const auto& Nb = state.local_nonce();\n            const std::uint8_t* Pkax = state.remote_public_key_x();\n            const std::uint8_t* PKbx = state.local_public_key_x();\n\n            const auto pass_key = funcs.g2( Pkax, PKbx, Na, Nb );\n            Obj.sm_pairing_numeric_output( static_cast< int >( pass_key ) );\n        }\n\n        struct meta_type :\n            details::pairing_output_capabilty_meta_type,\n            link_layer::details::valid_link_layer_option_meta_type {};\n        /** @endcond */\n    };\n\n    /**\n     * @brief mark that \"just works\" pairing is not acceptable\n     *\n     * This is the default, if the device has IO capabilties other than\n     * pairing_no_input and pairing_no_output (or pairing_yes_no and pairing_no_output)\n     * defined.\n     *\n     * @sa pairing_allow_just_works\n     */\n    struct pairing_no_just_works\n    {\n        /** @cond HIDDEN_SYMBOLS */\n        struct meta_type :\n            details::pairing_just_works_meta_type,\n            link_layer::details::valid_link_layer_option_meta_type {};\n        /** @endcond */\n    };\n\n    /**\n     * @brief mark that \"just works\" pairing is accepted, even when the device have\n     *        IO capabilities to exchange a pass key\n     *\n     * @sa pairing_no_just_works\n     */\n    struct pairing_allow_just_works\n    {\n        /** @cond HIDDEN_SYMBOLS */\n        struct meta_type :\n            details::pairing_just_works_meta_type,\n            link_layer::details::valid_link_layer_option_meta_type {};\n        /** @endcond */\n    };\n\n    namespace details\n    {\n        template < typename ... Options >\n        class io_capabilities_matrix\n        {\n        public:\n            using input_capabilities  = typename find_by_meta_type< pairing_input_capabilty_meta_type, Options..., pairing_no_input >::type;\n            using output_capabilities = typename find_by_meta_type< pairing_output_capabilty_meta_type, Options..., pairing_no_output >::type;\n\n            static io_capabilities get_io_capabilities()\n            {\n                return output_capabilities::get_io_capabilities(input_capabilities());\n            }\n\n            static legacy_pairing_algorithm select_legacy_pairing_algorithm( std::uint8_t io_capability )\n            {\n                return select_legacy_pairing_algorithm( static_cast< io_capabilities >( io_capability ) );\n            }\n\n            static legacy_pairing_algorithm select_legacy_pairing_algorithm( io_capabilities io_capability )\n            {\n                return output_capabilities::select_legacy_pairing_algorithm( input_capabilities(), io_capability );\n            }\n\n            static lesc_pairing_algorithm select_lesc_pairing_algorithm( std::uint8_t io_capability )\n            {\n                return select_lesc_pairing_algorithm( static_cast< io_capabilities >( io_capability ) );\n            }\n\n            static lesc_pairing_algorithm select_lesc_pairing_algorithm( io_capabilities io_capability )\n            {\n                return output_capabilities::select_lesc_pairing_algorithm( input_capabilities(), io_capability );\n            }\n\n            static void sm_pairing_numeric_output( const std::array< std::uint8_t, 16 >& temp_key )\n            {\n                output_capabilities::sm_pairing_numeric_output( temp_key );\n            }\n\n            template < class S, class F >\n            static void sm_pairing_numeric_compare_output( const S& state, F& func )\n            {\n                output_capabilities::sm_pairing_numeric_compare_output( state, func );\n            }\n\n            static std::array< std::uint8_t, 16 > sm_pairing_passkey()\n            {\n                return input_capabilities::sm_pairing_passkey();\n            }\n\n            template < class S >\n            static void sm_pairing_request_yes_no( S& state )\n            {\n                input_capabilities::sm_pairing_request_yes_no( state );\n            }\n        };\n    }\n}\n\n#endif // include guard\n"
  },
  {
    "path": "bluetoe/sm/include/bluetoe/oob_authentication.hpp",
    "content": "#ifndef BLUETOE_SM_INCLUDE_OOB_AUTHENTICATION_HPP\n#define BLUETOE_SM_INCLUDE_OOB_AUTHENTICATION_HPP\n\n#include <bluetoe/ll_meta_types.hpp>\n\n#include <cstdint>\n#include <array>\n#include <utility>\n#include <tuple>\n\nnamespace bluetoe {\n\n    namespace details {\n        struct oob_authentication_callback_meta_type {};\n    }\n\n    /**\n     * @brief 128 bit of out of band authentication data\n     */\n    using oob_authentication_data_t = std::array< std::uint8_t, 16 >;\n\n    /**\n     * @brief interface to provide OOB data to the pairing process\n     *\n     * Provides a mean to install a callback that is called, once a pairing request is accepted, to provide\n     * the OOB key for the requesting device.\n     *\n     * The parameter T have to be a class type with following none static member\n     * function:\n     *\n     * std::pair< bool, bluetoe::oob_authentication_data_t > sm_oob_authentication_data( const bluetoe::link_layer::device_address& address );\n     *\n     * If the first member of the returned pair is true, the second member contains the OOB data for the requesting device identified\n     * by the given address.\n     *\n     * This option is ment to be passed as a link layer option to the selected device binding.\n     */\n    template < typename T, T& Obj >\n    class oob_authentication_callback\n    {\n        /** @cond HIDDEN_SYMBOLS */\n    public:\n        oob_authentication_callback()\n            : oob_data_present_( false )\n        {\n        }\n\n        void request_oob_data_presents_for_remote_device( const bluetoe::link_layer::device_address& address )\n        {\n            std::tie( oob_data_present_, oob_data_ ) = Obj.sm_oob_authentication_data( address );\n        }\n\n        bool has_oob_data_for_remote_device() const\n        {\n            return oob_data_present_;\n        }\n\n        oob_authentication_data_t get_oob_data_for_last_remote_device() const\n        {\n            return oob_data_;\n        };\n\n        struct meta_type :\n            details::oob_authentication_callback_meta_type,\n            link_layer::details::valid_link_layer_option_meta_type {};\n\n    private:\n        bool oob_data_present_;\n        std::array< std::uint8_t, 16 > oob_data_;\n        /** @endcond */\n    };\n\n    namespace details {\n        class no_oob_authentication\n        {\n        public:\n            void request_oob_data_presents_for_remote_device( const bluetoe::link_layer::device_address& )\n            {\n            }\n\n            bool has_oob_data_for_remote_device() const\n            {\n                return false;\n            }\n\n            std::array< std::uint8_t, 16 > get_oob_data_for_last_remote_device() const\n            {\n                return std::array< std::uint8_t, 16 >{{ 0 }};\n            };\n\n            struct meta_type :\n                details::oob_authentication_callback_meta_type,\n                link_layer::details::valid_link_layer_option_meta_type {};\n\n        };\n    }\n}\n\n#endif // include guard\n"
  },
  {
    "path": "bluetoe/sm/include/bluetoe/security_connection_data.hpp",
    "content": "#ifndef BLUETOE_SM_SECURITY_CONNECTION_DATA_HPP\n#define BLUETOE_SM_SECURITY_CONNECTION_DATA_HPP\n\nnamespace bluetoe {\n\n    namespace details {\n\n        using identity_resolving_key_t  = std::array< std::uint8_t, 16 >;\n        using uint128_t                 = std::array< std::uint8_t, 16 >;\n\n        using ecdh_public_key_t         = std::array< std::uint8_t, 64 >;\n        using ecdh_private_key_t        = std::array< std::uint8_t, 32 >;\n        using ecdh_shared_secret_t      = std::array< std::uint8_t, 32 >;\n\n        using io_capabilities_t         = std::array< std::uint8_t, 3 >;\n\n        /**\n         * @brief Tuple to store a longterm key along with\n         *        EDIV and Rand value to identify them later.\n         */\n        struct longterm_key_t\n        {\n            std::array< std::uint8_t, 16 >  longterm_key;\n            std::uint64_t                   rand;\n            std::uint16_t                   ediv;\n\n            bool operator==(const longterm_key_t& rhs) const\n            {\n                return longterm_key == rhs.longterm_key\n                    && rand         == rhs.rand\n                    && ediv         == rhs.ediv;\n            }\n\n            bool operator!=(const longterm_key_t& rhs) const\n            {\n                return !(*this == rhs);\n            }\n        };\n\n        struct security_manager_meta_type {};\n        struct authentication_requirements_flags_meta_type {};\n        struct bonding_data_base_meta_type {};\n        struct key_distribution_meta_type {};\n\n        enum class sm_pairing_state : std::uint8_t {\n            // both, legacy and LESC\n            idle,\n            pairing_completed,\n            user_response_wait,\n            user_response_failed,\n            user_response_success,\n            // legacy only\n            legacy_pairing_requested,\n            legacy_pairing_confirmed,\n            // LESC only\n            lesc_pairing_requested,\n            lesc_public_keys_exchanged,\n            lesc_pairing_confirm_send,\n            lesc_pairing_random_exchanged,\n        };\n\n        enum class authentication_requirements_flags : std::uint8_t {\n            bonding                 = 0x01,\n            mitm                    = 0x04,\n            secure_connections      = 0x08,\n            keypress                = 0x10\n        };\n\n        template < class OtherConnectionData >\n        class security_connection_data_base : public OtherConnectionData\n        {\n        public:\n            template < class ... Args >\n            security_connection_data_base( Args&&... args )\n                : OtherConnectionData( args... )\n                , state_( details::sm_pairing_state::idle )\n            {}\n\n            details::sm_pairing_state state() const\n            {\n                return state_;\n            }\n\n            void remote_connection_created( const bluetoe::link_layer::device_address& remote )\n            {\n                remote_addr_ = remote;\n            }\n\n            const bluetoe::link_layer::device_address& remote_address() const\n            {\n                return remote_addr_;\n            }\n\n            void error_reset()\n            {\n                state( details::sm_pairing_state::idle );\n            }\n\n        protected:\n            void state( details::sm_pairing_state state )\n            {\n                state_ = state;\n            }\n\n        private:\n            link_layer::device_address          remote_addr_;\n            details::sm_pairing_state           state_;\n        };\n\n        template < class OtherConnectionData >\n        class legacy_security_connection_data : public security_connection_data_base< OtherConnectionData >\n        {\n        public:\n            template < class ... Args >\n            legacy_security_connection_data( Args&&... args )\n                : security_connection_data_base< OtherConnectionData >( args... )\n            {}\n\n            void legacy_pairing_request( const details::uint128_t& srand, const details::uint128_t& p1, const details::uint128_t& p2 )\n            {\n                assert( this->state() == details::sm_pairing_state::idle );\n                this->state( details::sm_pairing_state::legacy_pairing_requested );\n                state_data_.pairing_state.c1_p1 = p1;\n                state_data_.pairing_state.c1_p2 = p2;\n                state_data_.pairing_state.srand = srand;\n            }\n\n            void pairing_confirm( const std::uint8_t* mconfirm_begin, const std::uint8_t* mconfirm_end )\n            {\n                assert( this->state() == details::sm_pairing_state::legacy_pairing_requested );\n                this->state( details::sm_pairing_state::legacy_pairing_confirmed );\n\n                assert( static_cast< std::size_t >( mconfirm_end - mconfirm_begin ) == state_data_.pairing_state.mconfirm.max_size() );\n                std::copy( mconfirm_begin, mconfirm_end, state_data_.pairing_state.mconfirm.begin() );\n            }\n\n            void legacy_pairing_completed( const details::uint128_t& short_term_key )\n            {\n                assert( this->state() == details::sm_pairing_state::legacy_pairing_confirmed );\n                this->state( details::sm_pairing_state::pairing_completed );\n\n                state_data_.completed_state.short_term_key = short_term_key;\n            }\n\n            template < class Link >\n            bool outgoing_security_manager_data_available( const Link& link ) const\n            {\n                return link.is_encrypted() && this->state() != details::sm_pairing_state::pairing_completed;\n            }\n\n            std::pair< bool, details::uint128_t > find_key( std::uint16_t ediv, std::uint64_t rand ) const\n            {\n                if ( ediv == 0 && rand == 0 && this->state() == details::sm_pairing_state::pairing_completed )\n                    return { true, state_data_.completed_state.short_term_key };\n\n                return std::pair< bool, details::uint128_t >{};\n            }\n\n            const details::uint128_t& c1_p1() const\n            {\n                return state_data_.pairing_state.c1_p1;\n            }\n\n            const details::uint128_t& c1_p2() const\n            {\n                return state_data_.pairing_state.c1_p2;\n            }\n\n            const details::uint128_t& srand() const\n            {\n                return state_data_.pairing_state.srand;\n            }\n\n            const details::uint128_t& mconfirm() const\n            {\n                return state_data_.pairing_state.mconfirm;\n            }\n\n            void pairing_algorithm( details::legacy_pairing_algorithm algo )\n            {\n                algorithm_ = algo;\n            }\n\n            details::legacy_pairing_algorithm legacy_pairing_algorithm() const\n            {\n                return algorithm_;\n            }\n\n            device_pairing_status local_device_pairing_status() const\n            {\n                if ( this->state() != details::sm_pairing_state::pairing_completed )\n                    return bluetoe::device_pairing_status::no_key;\n\n                return algorithm_ == details::legacy_pairing_algorithm::just_works\n                    ? device_pairing_status::unauthenticated_key\n                    : device_pairing_status::authenticated_key;\n            }\n\n            void passkey( const details::uint128_t& key )\n            {\n                state_data_.pairing_state.passkey = key;\n            }\n\n            details::uint128_t passkey() const\n            {\n                return state_data_.pairing_state.passkey;\n            }\n        private:\n            details::legacy_pairing_algorithm   algorithm_;\n\n            union {\n                struct {\n                    details::uint128_t c1_p1;\n                    details::uint128_t c1_p2;\n                    details::uint128_t srand;\n                    details::uint128_t mconfirm;\n                    details::uint128_t passkey;\n                }                                   pairing_state;\n\n                struct {\n                    details::uint128_t short_term_key;\n                }                                   completed_state;\n            }                       state_data_;\n        };\n\n        template < class OtherConnectionData >\n        class lesc_security_connection_data : public security_connection_data_base< OtherConnectionData >, public pairing_yes_no_response\n        {\n        public:\n            template < class ... Args >\n            lesc_security_connection_data( Args&&... args )\n                : security_connection_data_base< OtherConnectionData >( args... )\n            {}\n\n            void wait_for_user_response()\n            {\n                this->state( details::sm_pairing_state::user_response_wait );\n            }\n\n            void yes_no_response( bool response ) override\n            {\n                assert( this->state() == details::sm_pairing_state::user_response_wait );\n\n                this->state( response\n                    ? details::sm_pairing_state::user_response_success\n                    : details::sm_pairing_state::user_response_failed );\n            }\n\n            device_pairing_status local_device_pairing_status() const\n            {\n                return this->state() == details::sm_pairing_state::pairing_completed\n                    ? bluetoe::device_pairing_status::unauthenticated_key\n                    : bluetoe::device_pairing_status::no_key;\n            }\n\n            std::pair< bool, details::uint128_t > find_key( std::uint16_t ediv, std::uint64_t rand ) const\n            {\n                if ( this->state() == details::sm_pairing_state::pairing_completed && ediv == 0 && rand == 0 )\n                    return { true, long_term_key_ };\n\n                return std::pair< bool, details::uint128_t >{};\n            }\n\n            void pairing_requested( const io_capabilities_t& remote_io_caps )\n            {\n                assert( this->state() == details::sm_pairing_state::idle );\n                this->state( details::sm_pairing_state::lesc_pairing_requested );\n                remote_io_caps_ = remote_io_caps;\n            }\n\n            void public_key_exchanged(\n                const ecdh_private_key_t&   local_private_key,\n                const ecdh_public_key_t&    local_public_key,\n                const std::uint8_t*         remote_public_key,\n                const details::uint128_t&   nonce )\n            {\n                assert( this->state() == details::sm_pairing_state::lesc_pairing_requested );\n                this->state( details::sm_pairing_state::lesc_public_keys_exchanged );\n\n                local_private_key_ = local_private_key;\n                local_public_key_  = local_public_key;\n                local_nonce_       = nonce;\n                std::copy( remote_public_key, remote_public_key + remote_public_key_.size(), remote_public_key_.begin() );\n            }\n\n            void pairing_confirm_send()\n            {\n                assert( this->state() == details::sm_pairing_state::lesc_public_keys_exchanged );\n                this->state( details::sm_pairing_state::lesc_pairing_confirm_send );\n            }\n\n            void pairing_random_exchanged( const std::uint8_t* remote_nonce )\n            {\n                assert( this->state() == details::sm_pairing_state::lesc_pairing_confirm_send );\n                this->state( details::sm_pairing_state::lesc_pairing_random_exchanged );\n\n                std::copy( remote_nonce, remote_nonce + 16, remote_nonce_.begin() );\n            }\n\n            void lesc_pairing_completed( const details::uint128_t& long_term_key )\n            {\n                assert( this->state() == details::sm_pairing_state::lesc_pairing_random_exchanged\n                     || this->state() == details::sm_pairing_state::user_response_success );\n\n                this->state( details::sm_pairing_state::pairing_completed );\n\n                long_term_key_ = long_term_key;\n            }\n\n            const uint128_t& local_nonce() const\n            {\n                return local_nonce_;\n            }\n\n            const uint128_t& remote_nonce() const\n            {\n                return remote_nonce_;\n            }\n\n            const std::uint8_t* local_public_key_x() const\n            {\n                return local_public_key_.data();\n            }\n\n            const std::uint8_t* remote_public_key_x() const\n            {\n                return remote_public_key_.data();\n            }\n\n            const std::uint8_t* remote_public_key() const\n            {\n                return remote_public_key_.data();\n            }\n\n            const std::uint8_t* local_private_key() const\n            {\n                return local_private_key_.data();\n            }\n\n            const io_capabilities_t& remote_io_caps() const\n            {\n                return remote_io_caps_;\n            }\n\n            void pairing_algorithm( details::lesc_pairing_algorithm algo )\n            {\n                algorithm_ = algo;\n            }\n\n            details::lesc_pairing_algorithm lesc_pairing_algorithm() const\n            {\n                return algorithm_;\n            }\n        private:\n            enum lesc_pairing_algorithm         algorithm_;\n\n            ecdh_private_key_t                  local_private_key_;\n            ecdh_public_key_t                   local_public_key_;\n            ecdh_public_key_t                   remote_public_key_;\n            uint128_t                           local_nonce_;\n            uint128_t                           remote_nonce_;\n            io_capabilities_t                   remote_io_caps_;\n            uint128_t                           long_term_key_;\n        };\n\n        template < class OtherConnectionData >\n        class security_connection_data : public security_connection_data_base< OtherConnectionData >, public pairing_yes_no_response\n        {\n        public:\n            template < class ... Args >\n            security_connection_data( Args&&... args )\n                : security_connection_data_base< OtherConnectionData >( args... )\n            {}\n\n            void wait_for_user_response()\n            {\n                this->state( details::sm_pairing_state::user_response_wait );\n            }\n\n            void yes_no_response( bool response ) override\n            {\n                assert( this->state() == details::sm_pairing_state::user_response_wait );\n\n                this->state( response\n                    ? details::sm_pairing_state::user_response_success\n                    : details::sm_pairing_state::user_response_failed );\n            }\n\n            void pairing_algorithm( details::legacy_pairing_algorithm algo )\n            {\n                state_data_.legacy_state.algorithm = algo;\n            }\n\n            details::legacy_pairing_algorithm legacy_pairing_algorithm() const\n            {\n                return state_data_.legacy_state.algorithm;\n            }\n\n            void pairing_algorithm( details::lesc_pairing_algorithm algo )\n            {\n                state_data_.lesc_state.algorithm = algo;\n            }\n\n            details::lesc_pairing_algorithm lesc_pairing_algorithm() const\n            {\n                return state_data_.lesc_state.algorithm;\n            }\n\n            void legacy_pairing_request( const details::uint128_t& srand, const details::uint128_t& p1, const details::uint128_t& p2 )\n            {\n                assert( this->state() == details::sm_pairing_state::idle );\n                this->state( details::sm_pairing_state::legacy_pairing_requested );\n                state_data_.legacy_state.states.pairing_state.c1_p1 = p1;\n                state_data_.legacy_state.states.pairing_state.c1_p2 = p2;\n                state_data_.legacy_state.states.pairing_state.srand = srand;\n            }\n\n            void pairing_confirm( const std::uint8_t* mconfirm_begin, const std::uint8_t* mconfirm_end )\n            {\n                assert( this->state() == details::sm_pairing_state::legacy_pairing_requested );\n                this->state( details::sm_pairing_state::legacy_pairing_confirmed );\n\n                assert( static_cast< std::size_t >( mconfirm_end - mconfirm_begin ) == state_data_.legacy_state.states.pairing_state.mconfirm.max_size() );\n                std::copy( mconfirm_begin, mconfirm_end, state_data_.legacy_state.states.pairing_state.mconfirm.begin() );\n            }\n\n            void legacy_pairing_completed( const details::uint128_t& short_term_key )\n            {\n                assert( this->state() == details::sm_pairing_state::legacy_pairing_confirmed );\n                this->state( details::sm_pairing_state::pairing_completed );\n\n                long_term_key_ = short_term_key;\n\n                pairing_status_ = state_data_.legacy_state.algorithm == details::legacy_pairing_algorithm::just_works\n                    ? device_pairing_status::unauthenticated_key\n                    : device_pairing_status::authenticated_key;\n            }\n\n            void lesc_pairing_completed( const details::uint128_t& long_term_key )\n            {\n                assert( this->state() == details::sm_pairing_state::lesc_pairing_random_exchanged\n                     || this->state() == details::sm_pairing_state::user_response_success );\n\n                this->state( details::sm_pairing_state::pairing_completed );\n\n                long_term_key_ = long_term_key;\n\n                pairing_status_ = state_data_.lesc_state.algorithm == details::lesc_pairing_algorithm::just_works\n                    ? device_pairing_status::unauthenticated_key\n                    : device_pairing_status::authenticated_key;\n            }\n\n            const details::uint128_t& c1_p1() const\n            {\n                return state_data_.legacy_state.states.pairing_state.c1_p1;\n            }\n\n            const details::uint128_t& c1_p2() const\n            {\n                return state_data_.legacy_state.states.pairing_state.c1_p2;\n            }\n\n            const details::uint128_t& srand() const\n            {\n                return state_data_.legacy_state.states.pairing_state.srand;\n            }\n\n            const details::uint128_t& mconfirm() const\n            {\n                return state_data_.legacy_state.states.pairing_state.mconfirm;\n            }\n\n            void passkey( const details::uint128_t& key )\n            {\n                state_data_.legacy_state.states.pairing_state.passkey = key;\n            }\n\n            details::uint128_t passkey() const\n            {\n                return state_data_.legacy_state.states.pairing_state.passkey;\n            }\n\n            void public_key_exchanged(\n                const ecdh_private_key_t&   local_private_key,\n                const ecdh_public_key_t&    local_public_key,\n                const std::uint8_t*         remote_public_key,\n                const details::uint128_t&   nonce )\n            {\n                assert( this->state() == details::sm_pairing_state::lesc_pairing_requested );\n                this->state( details::sm_pairing_state::lesc_public_keys_exchanged );\n\n                state_data_.lesc_state.local_private_key_ = local_private_key;\n                state_data_.lesc_state.local_public_key_  = local_public_key;\n                state_data_.lesc_state.local_nonce_       = nonce;\n                std::copy( remote_public_key, remote_public_key + state_data_.lesc_state.remote_public_key_.size(), state_data_.lesc_state.remote_public_key_.begin() );\n            }\n\n            void pairing_confirm_send()\n            {\n                assert( this->state() == details::sm_pairing_state::lesc_public_keys_exchanged );\n                this->state( details::sm_pairing_state::lesc_pairing_confirm_send );\n            }\n\n            void pairing_random_exchanged( const std::uint8_t* remote_nonce )\n            {\n                assert( this->state() == details::sm_pairing_state::lesc_pairing_confirm_send );\n                this->state( details::sm_pairing_state::lesc_pairing_random_exchanged );\n\n                std::copy( remote_nonce, remote_nonce + 16, state_data_.lesc_state.remote_nonce_.begin() );\n            }\n\n            void pairing_requested( const io_capabilities_t& remote_io_caps )\n            {\n                assert( this->state() == details::sm_pairing_state::idle );\n                this->state( details::sm_pairing_state::lesc_pairing_requested );\n                state_data_.lesc_state.remote_io_caps_ = remote_io_caps;\n            }\n\n            const uint128_t& local_nonce() const\n            {\n                return state_data_.lesc_state.local_nonce_;\n            }\n\n            const uint128_t& remote_nonce() const\n            {\n                return state_data_.lesc_state.remote_nonce_;\n            }\n\n            const std::uint8_t* local_public_key_x() const\n            {\n                return state_data_.lesc_state.local_public_key_.data();\n            }\n\n            const std::uint8_t* remote_public_key_x() const\n            {\n                return state_data_.lesc_state.remote_public_key_.data();\n            }\n\n            const std::uint8_t* remote_public_key() const\n            {\n                return state_data_.lesc_state.remote_public_key_.data();\n            }\n\n            const std::uint8_t* local_private_key() const\n            {\n                return state_data_.lesc_state.local_private_key_.data();\n            }\n\n            const io_capabilities_t& remote_io_caps() const\n            {\n                return state_data_.lesc_state.remote_io_caps_;\n            }\n\n            template < class Link >\n            bool outgoing_security_manager_data_available( const Link& link ) const\n            {\n                return link.is_encrypted() && this->state() != details::sm_pairing_state::pairing_completed;\n            }\n\n            std::pair< bool, details::uint128_t > find_key( std::uint16_t ediv, std::uint64_t rand ) const\n            {\n                if ( this->state() == details::sm_pairing_state::pairing_completed && ediv == 0 && rand == 0 )\n                    return { true, long_term_key_ };\n\n                return std::pair< bool, details::uint128_t >{};\n            }\n\n            device_pairing_status local_device_pairing_status() const\n            {\n                if ( this->state() != details::sm_pairing_state::pairing_completed )\n                    return bluetoe::device_pairing_status::no_key;\n\n                return pairing_status_;\n            }\n\n        private:\n            details::uint128_t                  long_term_key_;\n            device_pairing_status               pairing_status_;\n\n            union {\n                struct {\n                    union {\n                        struct {\n                            details::uint128_t c1_p1;\n                            details::uint128_t c1_p2;\n                            details::uint128_t srand;\n                            details::uint128_t mconfirm;\n                            details::uint128_t passkey;\n                        }                                   pairing_state;\n                    } states;\n                    enum legacy_pairing_algorithm    algorithm;\n                }                                           legacy_state;\n\n                struct {\n                    ecdh_private_key_t          local_private_key_;\n                    ecdh_public_key_t           local_public_key_;\n                    ecdh_public_key_t           remote_public_key_;\n                    uint128_t                   local_nonce_;\n                    uint128_t                   remote_nonce_;\n                    io_capabilities_t           remote_io_caps_;\n                    enum lesc_pairing_algorithm algorithm;\n                }                                           lesc_state;\n            } state_data_;\n        };\n    }\n}\n\n#endif\n"
  },
  {
    "path": "bluetoe/sm/include/bluetoe/security_manager.hpp",
    "content": "#ifndef BLUETOE_SM_SECURITY_MANAGER_HPP\n#define BLUETOE_SM_SECURITY_MANAGER_HPP\n\n#include <cstddef>\n#include <cstdint>\n#include <cassert>\n#include <array>\n#include <algorithm>\n\n#include <bluetoe/codes.hpp>\n#include <bluetoe/address.hpp>\n#include <bluetoe/link_state.hpp>\n#include <bluetoe/pairing_status.hpp>\n#include <bluetoe/ll_meta_types.hpp>\n#include <bluetoe/oob_authentication.hpp>\n#include <bluetoe/meta_tools.hpp>\n#include <bluetoe/io_capabilities.hpp>\n#include <bluetoe/l2cap_channels.hpp>\n#include <bluetoe/security_connection_data.hpp>\n\nnamespace bluetoe {\n\n    namespace details {\n\n        enum class sm_error_codes : std::uint8_t {\n            passkey_entry_failed        = 0x01,\n            oob_not_available           = 0x02,\n            authentication_requirements = 0x03,\n            confirm_value_failed        = 0x04,\n            pairing_not_supported       = 0x05,\n            encryption_key_size         = 0x06,\n            command_not_supported       = 0x07,\n            unspecified_reason          = 0x08,\n            repeated_attempts           = 0x09,\n            invalid_parameters          = 0x0a,\n            dhkey_check_failed          = 0x0b,\n            numeric_comparison_failed   = 0x0c,\n            br_edr_pairing_in_progress  = 0x0d,\n            crosstransport_key_derivation_generation_not_allowed = 0x0e\n        };\n\n        enum class sm_opcodes : std::uint8_t {\n            pairing_request          = 0x01,\n            pairing_response,\n            pairing_confirm,\n            pairing_random,\n            pairing_failed,\n            encryption_information,\n            central_identification,\n            identity_information,\n            identity_address_information,\n            signing_information,\n            security_request,\n            pairing_public_key,\n            pairing_dhkey_check,\n            pairing_keypress_notification\n        };\n    }\n\n    /**\n     * @brief access to a user defined key data base\n     *\n     * The provided implementation has to implement the following functions:\n     *\n     *   template < class Radio >\n     *   longterm_key_t create_new_bond( Radio& radio, const bluetoe::link_layer::device_address& mac );\n     *\n     *   void store_bond(\n     *       const bluetoe::details::longterm_key_t& key,\n     *       const bluetoe::link_layer::device_address& mac)\n     *\n     *   std::pair< bool, details::uint128_t > find_key( std::uint16_t ediv, std::uint64_t rand, const bluetoe::link_layer::device_address& remote_address ) const;\n     *\n     *   template < class Connection >\n     *   void restore_cccds( Connection& connection );\n     *\n     * create_new_bond() is used to create a longterm key für a bond with the given device. `radio` can be used\n     * to generate random numbers.\n     *\n     * store_bond() is used to store a key that was either created by store_bond(), or during the LESC paring process.\n     *\n     * find_key() will be called to lookup a stored long term key. If it does not exists, the function should return\n     * a pair with the first member set to false.\n     *\n     * This will also set bonding flags in the pairing response to \"Bonding\".\n     *\n     * @tparam Obj type that implements the given requirements\n     * @tparam obj instance that implements the given requirements\n     */\n    template < class Obj, Obj& obj >\n    struct bonding_data_base\n    {\n        /** @cond HIDDEN_SYMBOLS */\n        struct meta_type :  link_layer::details::valid_link_layer_option_meta_type,\n                            details::authentication_requirements_flags_meta_type,\n                            details::bonding_data_base_meta_type,\n                            details::key_distribution_meta_type {};\n\n        static constexpr std::uint8_t flags = static_cast< std::uint8_t >(\n            details::authentication_requirements_flags::bonding );\n\n        // Data that has to be added by the bonding data base\n        template < class OtherConnectionData >\n        class bonding_db_data_t : public OtherConnectionData\n        {\n        public:\n            std::pair< bool, details::uint128_t > find_key( std::uint16_t ediv, std::uint64_t rand ) const\n            {\n                const auto local_key = OtherConnectionData::find_key( ediv, rand );\n\n                if ( local_key.first )\n                    return local_key;\n\n                return obj.find_key( ediv, rand, this->remote_address() );\n            }\n\n            template < class Radio, class Connection >\n            void arm_key_distribution( Radio& radio, const Connection& connection )\n            {\n                pending_encryption_information = true;\n                pending_central_identification = true;\n\n                pending_key = obj.create_new_bond( radio, connection.remote_address() );\n                obj.store_bond( pending_key, connection );\n            }\n\n            template < typename Connection >\n            void store_lesc_key_in_bond_db( const details::uint128_t& key, const Connection& connection )\n            {\n                obj.store_bond( details::longterm_key_t{ key, 0u, 0u }, connection );\n            }\n\n            template < typename Connection >\n            void distribute_keys( std::uint8_t* output, std::size_t& out_size, Connection& connection )\n            {\n                out_size = 0;\n\n                if ( connection.security_attributes().is_encrypted )\n                {\n                    if ( pending_encryption_information )\n                    {\n                        pending_encryption_information = false;\n\n                        output[ 0 ] = static_cast< std::uint8_t >( details::sm_opcodes::encryption_information );\n                        std::copy( pending_key.longterm_key.begin(), pending_key.longterm_key.end(), &output[ 1 ] );\n                        std::fill( pending_key.longterm_key.begin(), pending_key.longterm_key.end(), 0 );\n\n                        out_size = 17;\n                    }\n                    else if ( pending_central_identification )\n                    {\n                        pending_central_identification = false;\n\n                        output[ 0 ] = static_cast< std::uint8_t >( details::sm_opcodes::central_identification );\n                        details::write_16bit( &output[ 1 ], pending_key.ediv );\n                        details::write_64bit( &output[ 3 ], pending_key.rand );\n\n                        out_size = 11;\n                    }\n                }\n            }\n\n            template < typename Connection >\n            void restore_bonded_cccds( Connection& connection )\n            {\n                obj.restore_cccds( connection );\n            }\n\n        private:\n            bool pending_encryption_information;\n            bool pending_central_identification;\n            details::longterm_key_t pending_key;\n        };\n\n        static constexpr std::uint8_t request_key_flags = 0x01;\n\n        /** @endcond */\n    };\n\n    /** @cond HIDDEN_SYMBOLS */\n    struct no_bonding_data_base\n    {\n        struct meta_type :  link_layer::details::valid_link_layer_option_meta_type,\n                            details::authentication_requirements_flags_meta_type,\n                            details::bonding_data_base_meta_type {};\n\n        template < class OtherConnectionData >\n        struct bonding_db_data_t : OtherConnectionData\n        {\n            template < class Radio, class Connection >\n            void arm_key_distribution( Radio&, const Connection& )\n            {\n            }\n\n            template < typename Connection >\n            void distribute_keys( std::uint8_t*, std::size_t& out_size, Connection& )\n            {\n                out_size = 0;\n            }\n\n            template < typename Connection >\n            void store_lesc_key_in_bond_db( const details::uint128_t&, const Connection& )\n            {\n            }\n\n            template < typename Connection >\n            void restore_bonded_cccds( Connection& )\n            {\n            }\n        };\n\n    };\n\n    struct no_key_distribution\n    {\n        struct meta_type :  link_layer::details::valid_link_layer_option_meta_type,\n                            details::key_distribution_meta_type {};\n\n        static constexpr std::uint8_t request_key_flags = 0;\n    };\n    /** @endcond */\n\n    namespace details {\n\n        inline void error_response( details::sm_error_codes error_code, std::uint8_t* output, std::size_t& out_size )\n        {\n            output[ 0 ] = static_cast< std::uint8_t >( sm_opcodes::pairing_failed );\n            output[ 1 ] = static_cast< std::uint8_t >( error_code );\n\n            out_size = 2;\n        }\n\n        template < typename ... Options >\n        struct accumulate_authentication_requirements_flags;\n\n        template <>\n        struct accumulate_authentication_requirements_flags< std::tuple<> >\n        {\n            static constexpr std::uint8_t flags = 0;\n        };\n\n        template < typename Option, class ... Options >\n        struct accumulate_authentication_requirements_flags< std::tuple< Option, Options... > > :\n            accumulate_authentication_requirements_flags< std::tuple< Options... > >\n        {\n            static constexpr std::uint8_t flags = Option::flags\n                | accumulate_authentication_requirements_flags< std::tuple< Options... > >::flags;\n        };\n\n        // features required by legacy and by lesc pairing\n        template < typename SecurityFunctions, template < class OtherConnectionData > class ConnectionData, typename ... Options >\n        class security_manager_base :\n            protected details::find_by_meta_type<\n                details::oob_authentication_callback_meta_type,\n                Options...,\n                details::no_oob_authentication >::type\n        {\n        protected:\n            static constexpr std::uint8_t authentication_requirements_flags =\n                accumulate_authentication_requirements_flags<\n                    typename find_all_by_meta_type< authentication_requirements_flags_meta_type, Options... >::type\n                >::flags;\n\n            using bonding_data_base_t = typename details::find_by_meta_type<\n                details::bonding_data_base_meta_type,\n                Options...,\n                no_bonding_data_base >::type;\n\n            using key_distribution_t = typename details::find_by_meta_type<\n                details::key_distribution_meta_type,\n                Options...,\n                no_key_distribution >::type;\n\n            template < class Connection >\n            void error_response( details::sm_error_codes error_code, std::uint8_t* output, std::size_t& out_size, Connection& state )\n            {\n                state.error_reset();\n                details::error_response( error_code, output, out_size );\n            }\n\n            using io_device_t = io_capabilities_matrix< Options... >;\n\n            static constexpr std::uint8_t   min_max_key_size = 7;\n            static constexpr std::uint8_t   max_max_key_size = 16;\n            static constexpr std::size_t    pairing_req_resp_size = 7;\n\n            template < class Connection >\n            void legacy_handle_pairing_request( const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size, Connection& );\n\n            void create_pairing_response( std::uint8_t* output, std::size_t& out_size, const io_capabilities_t& io_caps );\n\n            template < class Connection >\n            void legacy_handle_pairing_confirm( const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size, Connection& );\n\n            template < class Connection >\n            void legacy_handle_pairing_random( const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size, Connection& );\n\n            template < class Connection >\n            uint128_t legacy_create_temporary_key( Connection& );\n\n            template < class Connection >\n            uint128_t legacy_temporary_key( const Connection& ) const;\n\n            details::legacy_pairing_algorithm legacy_select_pairing_algorithm( std::uint8_t io_capability, std::uint8_t oob_data_flag, std::uint8_t auth_req, bool has_oob_data );\n\n            details::uint128_t legacy_c1_p1(\n                const std::uint8_t* input, const std::uint8_t* output,\n                const bluetoe::link_layer::device_address& initiating_device,\n                const bluetoe::link_layer::device_address& responding_device );\n\n            details::uint128_t legacy_c1_p2(\n                const bluetoe::link_layer::device_address& initiating_device,\n                const bluetoe::link_layer::device_address& responding_device );\n\n            static constexpr std::size_t    public_key_exchange_size = 65;\n            static constexpr std::size_t    pairing_confirm_size     = 17;\n            static constexpr std::size_t    pairing_random_size      = 17;\n            static constexpr std::size_t    pairing_dhkey_check_size = 17;\n\n            template < class Connection >\n            void lesc_handle_pairing_request( const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size, Connection& );\n\n            template < class Connection >\n            void lesc_handle_pairing_public_key( const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size, Connection& );\n\n            template < class Connection >\n            void lesc_handle_pairing_random( const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size, Connection& );\n\n            template < class Connection >\n            void lesc_handle_pairing_dhkey_check( const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size, Connection& );\n\n            template < class Connection >\n            bool lesc_security_manager_output_available( Connection& ) const;\n\n            template < class Connection >\n            void lesc_l2cap_output( std::uint8_t* output, std::size_t& out_size, Connection& );\n\n            details::io_capabilities_t legacy_local_io_caps() const;\n            details::io_capabilities_t lesc_local_io_caps() const;\n\n            details::lesc_pairing_algorithm lesc_select_pairing_algorithm( std::uint8_t io_capability, std::uint8_t oob_data_flag, std::uint8_t auth_req, bool has_oob_data );\n\n            SecurityFunctions& security_functions()\n            {\n                return static_cast< SecurityFunctions& >( *this );\n            }\n\n            const SecurityFunctions& security_functions() const\n            {\n                return static_cast< const SecurityFunctions& >( *this );\n            }\n        };\n\n        template < typename SecurityFunctions, template < class OtherConnectionData > class ConnectionData, typename ... Options >\n        class legacy_security_manager_impl : public security_manager_base< SecurityFunctions, ConnectionData, Options... >\n        {\n        public:\n            /** @cond HIDDEN_SYMBOLS */\n\n            template < class Connection >\n            void l2cap_input( const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size, Connection& );\n\n            template < class Connection >\n            void l2cap_output( std::uint8_t* output, std::size_t& out_size, Connection& );\n\n            static constexpr std::uint16_t channel_id               = l2cap_channel_ids::sm;\n            static constexpr std::size_t   minimum_channel_mtu_size = default_att_mtu_size;\n            static constexpr std::size_t   maximum_channel_mtu_size = default_att_mtu_size;\n\n            using base_t = security_manager_base< SecurityFunctions, ConnectionData, Options... >;\n\n            template < class OtherConnectionData >\n            using channel_data_t = typename base_t::bonding_data_base_t::template bonding_db_data_t< ConnectionData< OtherConnectionData > >;\n            /** @endcond */\n        };\n\n        template < typename SecurityFunctions, template < class OtherConnectionData > class ConnectionData, typename ... Options >\n        class lesc_security_manager_impl : public security_manager_base< SecurityFunctions, ConnectionData, Options... >\n        {\n        public:\n            /** @cond HIDDEN_SYMBOLS */\n            template < class Connection >\n            void l2cap_input( const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size, Connection& );\n\n            template < class Connection >\n            void l2cap_output( std::uint8_t* output, std::size_t& out_size, Connection& );\n\n            static constexpr std::uint16_t channel_id               = l2cap_channel_ids::sm;\n            static constexpr std::size_t   minimum_channel_mtu_size = default_lesc_mtu_size;\n            static constexpr std::size_t   maximum_channel_mtu_size = default_lesc_mtu_size;\n\n            using base_t = security_manager_base< SecurityFunctions, ConnectionData, Options... >;\n\n            template < class OtherConnectionData >\n            using channel_data_t = typename base_t::bonding_data_base_t::template bonding_db_data_t< ConnectionData< OtherConnectionData > >;\n            /** @endcond */\n        };\n\n        template < typename SecurityFunctions, template < class OtherConnectionData > class ConnectionData, typename ... Options >\n        class security_manager_impl : public security_manager_base< SecurityFunctions, ConnectionData, Options... >\n        {\n        public:\n            /** @cond HIDDEN_SYMBOLS */\n            template < class Connection >\n            void l2cap_input( const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size, Connection& );\n\n            template < class Connection >\n            void l2cap_output( std::uint8_t* output, std::size_t& out_size, Connection& );\n\n            static constexpr std::uint16_t channel_id               = l2cap_channel_ids::sm;\n            static constexpr std::size_t   minimum_channel_mtu_size = default_lesc_mtu_size;\n            static constexpr std::size_t   maximum_channel_mtu_size = default_lesc_mtu_size;\n\n            using base_t = security_manager_base< SecurityFunctions, ConnectionData, Options... >;\n\n            template < class OtherConnectionData >\n            using channel_data_t = typename base_t::bonding_data_base_t::template bonding_db_data_t< ConnectionData< OtherConnectionData > >;\n\n        private:\n            using security_manager_base< SecurityFunctions, ConnectionData, Options... >::security_functions;\n\n            template < class Connection >\n            void handle_pairing_request( const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size, Connection& );\n\n            /** @endcond */\n        };\n\n    } // namespace details\n\n    /**\n     * @brief A Security manager implementation that supports legacy pairing.\n     *\n     * The legacy_security_manager supports legacy pairing. To do so, the security manager needs a hardware binding\n     * that supports the required cryptographical primities. Usually this is the SM implementation with the least resource\n     * costs.\n     *\n     * By default, this security manager only implements \"just works\" pairing. To implement other pairing methods, the\n     * library must get some details about how to handle IO.\n     *\n     * @sa pairing_yes_no\n     * @sa pairing_keyboard\n     * @sa pairing_numeric_output\n     *\n     * @sa bonding_data_base\n     *\n     * @sa lesc_security_manager\n     * @sa security_manager\n     * @sa no_security_manager\n     */\n    class legacy_security_manager\n    {\n    public:\n        /** @cond HIDDEN_SYMBOLS */\n        template < typename SecurityFunctions, typename ... Options >\n        using impl = details::legacy_security_manager_impl< SecurityFunctions, details::legacy_security_connection_data, Options... >;\n\n        struct meta_type :  link_layer::details::valid_link_layer_option_meta_type,\n                            details::security_manager_meta_type {};\n        /** @endcond */\n    };\n\n    /**\n     * @brief A Security manager that implements only LESC pairing.\n     *\n     * This is the current default. The SM will reject every attempt to pair to the device without\n     * LE Secure Connections.\n     *\n     * By default, this security manager only implements \"just works\" pairing. To implement other pairing methods, the\n     * library must get some details about how to handle IO.\n     *\n     * @sa pairing_yes_no\n     * @sa pairing_keyboard\n     * @sa pairing_numeric_output\n     *\n     * @sa bonding_data_base\n     *\n     * @sa legacy_security_manager\n     * @sa security_manager\n     * @sa no_security_manager\n     */\n    class lesc_security_manager\n    {\n    public:\n        /** @cond HIDDEN_SYMBOLS */\n        template < typename SecurityFunctions, typename ... Options >\n        using impl = details::lesc_security_manager_impl< SecurityFunctions, details::lesc_security_connection_data, Options... >;\n\n        struct meta_type :  link_layer::details::valid_link_layer_option_meta_type,\n                            details::security_manager_meta_type {};\n        /** @endcond */\n    };\n\n    /**\n     * @brief A security manager that implpementes the full set of pairing methods (Legacy and LESC)\n     *\n     * By default, this security manager only implements \"just works\" pairing. To implement other pairing methods, the\n     * library must get some details about how to handle IO.\n     *\n     * @sa pairing_yes_no\n     * @sa pairing_keyboard\n     * @sa pairing_numeric_output\n     *\n     * @sa bonding_data_base\n     *\n     * @sa legacy_security_manager\n     * @sa lesc_security_manager\n     * @sa no_security_manager\n     */\n    class security_manager\n    {\n    public:\n        /** @cond HIDDEN_SYMBOLS */\n        template < typename SecurityFunctions, typename ... Options >\n        using impl = details::security_manager_impl< SecurityFunctions, details::security_connection_data, Options... >;\n\n        struct meta_type :  link_layer::details::valid_link_layer_option_meta_type,\n                            details::security_manager_meta_type {};\n\n        /** @endcond */\n    };\n\n    /**\n     * @brief implementation of the security manager, that actievly rejects every pairing attempt.\n     *\n     * Use this option, if you are sure, that you are not going to require encryption at all or if the\n     * required security measures are implemented on the application level.\n     *\n     * @sa legacy_security_manager\n     * @sa lesc_security_manager\n     * @sa security_manager\n     */\n    class no_security_manager\n    {\n    public:\n        /** @cond HIDDEN_SYMBOLS */\n        template < typename SecurityFunctions, typename ... >\n        class impl\n        {\n        public:\n            template < class OtherConnectionData >\n            class channel_data_t : public OtherConnectionData\n            {\n            public:\n                void remote_connection_created( const bluetoe::link_layer::device_address& )\n                {\n                }\n\n                device_pairing_status local_device_pairing_status() const\n                {\n                    return bluetoe::device_pairing_status::no_key;\n                }\n\n            };\n\n            template < class Connection >\n            void l2cap_input( const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size, Connection& );\n\n            template < class Connection >\n            void l2cap_output( std::uint8_t* output, std::size_t& out_size, Connection& );\n\n            static constexpr std::uint16_t channel_id               = l2cap_channel_ids::sm;\n            static constexpr std::size_t   minimum_channel_mtu_size = 0;\n            static constexpr std::size_t   maximum_channel_mtu_size = 0;\n        };\n\n        struct meta_type :  link_layer::details::valid_link_layer_option_meta_type,\n                            details::security_manager_meta_type {};\n        /** @endcond */\n    };\n\n    /**\n     * @brief requests bonding during pairing\n     *\n     * This will set bonding flags in the pairing response to \"Bonding\"\n     */\n    struct enable_bonding\n    {\n        /** @cond HIDDEN_SYMBOLS */\n        struct meta_type :  link_layer::details::valid_link_layer_option_meta_type,\n                            details::authentication_requirements_flags_meta_type {};\n\n        static constexpr std::uint8_t flags = static_cast< std::uint8_t >(\n            details::authentication_requirements_flags::bonding );\n        /** @endcond */\n    };\n\n    /**\n     * @brief set the MITM flag in the Authentication requirements flags of the\n     *        pairing response.\n     */\n    struct require_man_in_the_middle_protection\n    {\n        /** @cond HIDDEN_SYMBOLS */\n        struct meta_type :  link_layer::details::valid_link_layer_option_meta_type,\n                            details::authentication_requirements_flags_meta_type {};\n\n        static constexpr std::uint8_t flags = static_cast< std::uint8_t >(\n            details::authentication_requirements_flags::mitm );\n        /** @endcond */\n    };\n\n    /**\n     * @brief set the MITM flag in the Authentication requirements flags of the\n     *        pairing response.\n     */\n    struct enable_keypress_notifications\n    {\n        /** @cond HIDDEN_SYMBOLS */\n        struct meta_type :  link_layer::details::valid_link_layer_option_meta_type,\n                            details::authentication_requirements_flags_meta_type {};\n\n        static constexpr std::uint8_t flags = static_cast< std::uint8_t >(\n            details::authentication_requirements_flags::keypress );\n        /** @endcond */\n    };\n\n    /*\n     * Implementation\n     */\n    /** @cond HIDDEN_SYMBOLS */\n    template < typename SecurityFunctions, template < class OtherConnectionData > class ConnectionData, typename ... Options >\n    template < class Connection >\n    void details::security_manager_base< SecurityFunctions, ConnectionData, Options... >::legacy_handle_pairing_request(\n        const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size, Connection& state )\n    {\n        using namespace details;\n\n        if ( in_size != pairing_req_resp_size )\n            return this->error_response( sm_error_codes::invalid_parameters, output, out_size, state );\n\n        if ( state.state() != details::sm_pairing_state::idle )\n            return this->error_response( sm_error_codes::unspecified_reason, output, out_size, state );\n\n        const std::uint8_t io_capability                = input[ 1 ];\n        const std::uint8_t oob_data_flag                = input[ 2 ];\n        const std::uint8_t auth_req                     = input[ 3 ] & 0x1f;\n        const std::uint8_t max_key_size                 = input[ 4 ];\n        const std::uint8_t initiator_key_distribution   = input[ 5 ];\n        const std::uint8_t responder_key_distribution   = input[ 6 ];\n\n        if (\n            ( io_capability > static_cast< std::uint8_t >( io_capabilities::last ) )\n         || ( oob_data_flag & ~0x01 )\n         || ( max_key_size < min_max_key_size || max_key_size > max_max_key_size )\n         || ( initiator_key_distribution & 0xf0 )\n         || ( responder_key_distribution & 0xf0 )\n        )\n        {\n            return this->error_response( sm_error_codes::invalid_parameters, output, out_size, state );\n        }\n\n        this->request_oob_data_presents_for_remote_device( state.remote_address() );\n        state.pairing_algorithm( legacy_select_pairing_algorithm( io_capability, oob_data_flag, auth_req, this->has_oob_data_for_remote_device() ) );\n\n        create_pairing_response( output, out_size, legacy_local_io_caps() );\n\n        const details::uint128_t srand    = security_functions().create_srand();\n        const details::uint128_t p1       = legacy_c1_p1( input, output, state.remote_address(), security_functions().local_address() );\n        const details::uint128_t p2       = legacy_c1_p2( state.remote_address(), security_functions().local_address() );\n\n        state.legacy_pairing_request( srand, p1, p2 );\n    }\n\n    template < typename SecurityFunctions, template < class OtherConnectionData > class ConnectionData, typename ... Options >\n    inline void details::security_manager_base< SecurityFunctions, ConnectionData, Options... >::create_pairing_response( std::uint8_t* output, std::size_t& out_size, const io_capabilities_t& io_caps )\n    {\n        out_size = pairing_req_resp_size;\n        output[ 0 ] = static_cast< std::uint8_t >( sm_opcodes::pairing_response );\n        output[ 1 ] = io_caps[ 0 ];\n        output[ 2 ] = io_caps[ 1 ];\n        output[ 3 ] = io_caps[ 2 ];\n        output[ 4 ] = max_max_key_size;\n        output[ 5 ] = 0;\n        output[ 6 ] = key_distribution_t::request_key_flags;\n    }\n\n    template < typename SecurityFunctions, template < class OtherConnectionData > class ConnectionData, typename ... Options >\n    template < class Connection >\n    void details::security_manager_base< SecurityFunctions, ConnectionData, Options... >::legacy_handle_pairing_confirm(\n        const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size, Connection& state )\n    {\n        using namespace details;\n\n        static constexpr std::size_t    request_size = 17;\n\n        if ( in_size != request_size )\n            return this->error_response( sm_error_codes::invalid_parameters, output, out_size, state );\n\n        if ( state.state() != sm_pairing_state::legacy_pairing_requested )\n            return this->error_response( sm_error_codes::unspecified_reason, output, out_size, state );\n\n        // save mconfirm for later\n        state.pairing_confirm( &input[ 1 ], &input[ request_size ] );\n\n        out_size = request_size;\n        output[ 0 ] = static_cast< std::uint8_t >( sm_opcodes::pairing_confirm );\n\n        const auto temp_key = legacy_create_temporary_key( state );\n\n        io_device_t::sm_pairing_numeric_output( temp_key );\n\n        const auto sconfirm = security_functions().c1( temp_key, state.srand(), state.c1_p1(), state.c1_p2() );\n        std::copy( sconfirm.begin(), sconfirm.end(), &output[ 1 ] );\n    }\n\n    template < typename SecurityFunctions, template < class OtherConnectionData > class ConnectionData, typename ... Options >\n    template < class Connection >\n    void details::security_manager_base< SecurityFunctions, ConnectionData, Options... >::legacy_handle_pairing_random(\n        const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size, Connection& state )\n    {\n        using namespace details;\n\n        static constexpr std::size_t    pairing_random_size = 17;\n\n        if ( in_size != pairing_random_size )\n            return this->error_response( sm_error_codes::invalid_parameters, output, out_size, state );\n\n        if ( state.state() != sm_pairing_state::legacy_pairing_confirmed )\n            return this->error_response( sm_error_codes::unspecified_reason, output, out_size, state );\n\n        uint128_t mrand;\n        std::copy( &input[ 1 ], &input[ pairing_random_size ], mrand.begin() );\n        const uint128_t temp_key = legacy_temporary_key( state );\n\n        const auto mconfirm = security_functions().c1( temp_key, mrand, state.c1_p1(), state.c1_p2() );\n\n        if ( mconfirm != state.mconfirm() )\n            return this->error_response( sm_error_codes::confirm_value_failed, output, out_size, state );\n\n        out_size = pairing_random_size;\n        output[ 0 ] = static_cast< std::uint8_t >( sm_opcodes::pairing_random );\n\n        const auto srand = state.srand();\n        std::copy( srand.begin(), srand.end(), &output[ 1 ] );\n\n        const auto stk = security_functions().s1( temp_key, srand, mrand );\n        state.legacy_pairing_completed( stk );\n        state.arm_key_distribution( security_functions(), state );\n    }\n\n    template < typename SecurityFunctions, template < class OtherConnectionData > class ConnectionData, typename ... Options >\n    template < class Connection >\n    details::uint128_t details::security_manager_base< SecurityFunctions, ConnectionData, Options... >::legacy_create_temporary_key( Connection& state )\n    {\n        const auto algo = state.legacy_pairing_algorithm();\n\n        switch ( algo )\n        {\n            case legacy_pairing_algorithm::oob_authentication:\n                return this->get_oob_data_for_last_remote_device();\n\n            case legacy_pairing_algorithm::passkey_entry_display:\n            {\n                const auto key = security_functions().create_passkey();\n                state.passkey( key );\n\n                return key;\n            }\n\n            case legacy_pairing_algorithm::passkey_entry_input:\n            {\n\n                const auto key = io_device_t::sm_pairing_passkey();\n                state.passkey( key );\n\n                return key;\n            }\n\n            default:\n                break;\n        }\n\n        return uint128_t( { 0 } );\n    }\n\n    template < typename SecurityFunctions, template < class OtherConnectionData > class ConnectionData, typename ... Options >\n    template < class Connection >\n    details::uint128_t details::security_manager_base< SecurityFunctions, ConnectionData, Options... >::legacy_temporary_key( const Connection& state ) const\n    {\n        const auto algo = state.legacy_pairing_algorithm();\n\n        switch ( algo )\n        {\n            case legacy_pairing_algorithm::oob_authentication:\n                return this->get_oob_data_for_last_remote_device();\n\n            case legacy_pairing_algorithm::passkey_entry_display:\n            case legacy_pairing_algorithm::passkey_entry_input:\n                return state.passkey();\n\n            default:\n                break;\n        }\n\n        return uint128_t( { 0 } );\n    }\n\n    template < typename SecurityFunctions, template < class OtherConnectionData > class ConnectionData, typename ... Options >\n    details::legacy_pairing_algorithm details::security_manager_base< SecurityFunctions, ConnectionData, Options... >::legacy_select_pairing_algorithm( std::uint8_t io_capability, std::uint8_t oob_data_flag, std::uint8_t /* auth_req */, bool has_oob_data )\n    {\n        if ( oob_data_flag && has_oob_data )\n            return details::legacy_pairing_algorithm::oob_authentication;\n\n        return io_device_t::select_legacy_pairing_algorithm( io_capability );\n    }\n\n    template < typename SecurityFunctions, template < class OtherConnectionData > class ConnectionData, typename ... Options >\n    inline details::uint128_t details::security_manager_base< SecurityFunctions, ConnectionData, Options... >::legacy_c1_p1(\n        const std::uint8_t* input, const std::uint8_t* output,\n        const bluetoe::link_layer::device_address& initiating_device,\n        const bluetoe::link_layer::device_address& responding_device )\n    {\n        details::uint128_t result{ {\n            std::uint8_t( initiating_device.is_random() ? 0x01 : 0x00 ),\n            std::uint8_t( responding_device.is_random() ? 0x01 : 0x00 ) } };\n\n        std::copy( input, input + pairing_req_resp_size, &result[ 2 ] );\n        std::copy( output, output + pairing_req_resp_size, &result[ 2 + pairing_req_resp_size ] );\n\n        return result;\n    }\n\n    template < typename SecurityFunctions, template < class OtherConnectionData > class ConnectionData, typename ... Options >\n    inline details::uint128_t details::security_manager_base< SecurityFunctions, ConnectionData, Options... >::legacy_c1_p2(\n        const bluetoe::link_layer::device_address& initiating_device,\n        const bluetoe::link_layer::device_address& responding_device )\n    {\n        static constexpr std::size_t address_size_in_bytes = 6;\n        static constexpr std::uint8_t padding = 0;\n\n        details::uint128_t result;\n\n        std::copy( responding_device.begin(), responding_device.end(), result.begin() );\n        std::copy( initiating_device.begin(), initiating_device.end(), std::next( result.begin(), address_size_in_bytes ) );\n        std::fill( std::next( result.begin(), 2 * address_size_in_bytes ), result.end(), padding );\n\n        return result;\n    }\n\n    template < typename SecurityFunctions, template < class OtherConnectionData > class ConnectionData, typename ... Options >\n    template < class Connection >\n    void details::security_manager_base< SecurityFunctions, ConnectionData, Options... >::lesc_handle_pairing_request(\n        const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size, Connection& state )\n    {\n        using namespace details;\n\n        if ( in_size != pairing_req_resp_size )\n            return this->error_response( sm_error_codes::invalid_parameters, output, out_size, state );\n\n        if ( state.state() != details::sm_pairing_state::idle )\n            return this->error_response( sm_error_codes::unspecified_reason, output, out_size, state );\n\n        const std::uint8_t io_capability                = input[ 1 ];\n        const std::uint8_t oob_data_flag                = input[ 2 ];\n        const std::uint8_t auth_req                     = input[ 3 ];\n        const std::uint8_t max_key_size                 = input[ 4 ];\n        const std::uint8_t initiator_key_distribution   = input[ 5 ];\n        const std::uint8_t responder_key_distribution   = input[ 6 ];\n\n        if (\n            ( io_capability > static_cast< std::uint8_t >( io_capabilities::last ) )\n         || ( oob_data_flag & ~0x01 )\n         || ( max_key_size < min_max_key_size || max_key_size > max_max_key_size )\n         || ( initiator_key_distribution & 0xf0 )\n         || ( responder_key_distribution & 0xf0 )\n        )\n        {\n            return this->error_response( sm_error_codes::invalid_parameters, output, out_size, state );\n        }\n\n        if ( ( auth_req & static_cast< std::uint8_t >( authentication_requirements_flags::secure_connections ) ) == 0 )\n            return this->error_response( sm_error_codes::pairing_not_supported, output, out_size, state );\n\n        const io_capabilities_t remote_io_caps = {{ io_capability, oob_data_flag, auth_req }};\n\n        state.pairing_algorithm( lesc_select_pairing_algorithm( io_capability, oob_data_flag, auth_req, this->has_oob_data_for_remote_device() ) );\n        state.pairing_requested( remote_io_caps );\n        create_pairing_response( output, out_size, lesc_local_io_caps() );\n    }\n\n    template < typename SecurityFunctions, template < class OtherConnectionData > class ConnectionData, typename ... Options >\n    details::io_capabilities_t details::security_manager_base< SecurityFunctions, ConnectionData, Options... >::legacy_local_io_caps() const\n    {\n        static constexpr std::uint8_t oob_authentication_data_not_present                = 0x00;\n        static constexpr std::uint8_t oob_authentication_data_from_remote_device_present = 0x01;\n\n        return {{\n            static_cast< std::uint8_t >( io_device_t::get_io_capabilities() ),\n            this->has_oob_data_for_remote_device()\n            ? oob_authentication_data_from_remote_device_present\n            : oob_authentication_data_not_present,\n            authentication_requirements_flags }};\n    }\n\n    template < typename SecurityFunctions, template < class OtherConnectionData > class ConnectionData, typename ... Options >\n    details::io_capabilities_t details::security_manager_base< SecurityFunctions, ConnectionData, Options... >::lesc_local_io_caps() const\n    {\n        return {{\n            static_cast< std::uint8_t >( io_device_t::get_io_capabilities() ),\n            0,\n            authentication_requirements_flags | static_cast< std::uint8_t >( details::authentication_requirements_flags::secure_connections ) }};\n    }\n\n    template < typename SecurityFunctions, template < class OtherConnectionData > class ConnectionData, typename ... Options >\n    template < class Connection >\n    void details::security_manager_base< SecurityFunctions, ConnectionData, Options... >::lesc_handle_pairing_public_key(\n        const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size, Connection& state )\n    {\n        if ( in_size != public_key_exchange_size )\n            return this->error_response( details::sm_error_codes::invalid_parameters, output, out_size, state );\n\n        if ( state.state() != details::sm_pairing_state::lesc_pairing_requested )\n            return this->error_response( details::sm_error_codes::unspecified_reason, output, out_size, state );\n\n        assert( out_size >= public_key_exchange_size );\n\n        if ( !security_functions().is_valid_public_key( &input[ 1 ] ) )\n            return this->error_response( details::sm_error_codes::invalid_parameters, output, out_size, state );\n\n        output[ 0 ] = static_cast< std::uint8_t >( details::sm_opcodes::pairing_public_key );\n\n        out_size = public_key_exchange_size;\n        const auto& keys  = security_functions().generate_keys();\n        const auto& nonce = security_functions().select_random_nonce();\n\n        state.public_key_exchanged( keys.second, keys.first, &input[ 1 ], nonce );\n        std::copy( keys.first.begin(), keys.first.end(), &output[ 1 ] );\n    }\n\n    template < typename SecurityFunctions, template < class OtherConnectionData > class ConnectionData, typename ... Options >\n    template < class Connection >\n    void details::security_manager_base< SecurityFunctions, ConnectionData, Options... >::lesc_handle_pairing_random( const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size, Connection& state )\n    {\n        if ( in_size != pairing_random_size )\n            return this->error_response( details::sm_error_codes::invalid_parameters, output, out_size, state );\n\n        if ( state.state() != details::sm_pairing_state::lesc_pairing_confirm_send )\n            return this->error_response( details::sm_error_codes::unspecified_reason, output, out_size, state );\n\n        state.pairing_random_exchanged( input + 1 );\n\n        if ( state.lesc_pairing_algorithm() == lesc_pairing_algorithm::numeric_comparison )\n        {\n            io_device_t::sm_pairing_numeric_compare_output( state, security_functions() );\n            io_device_t::sm_pairing_request_yes_no( state );\n        }\n\n        if ( state.state() == details::sm_pairing_state::user_response_failed )\n            return this->error_response( details::sm_error_codes::passkey_entry_failed, output, out_size, state );\n\n        const auto& nonce = state.local_nonce();\n        out_size = pairing_random_size;\n        output[ 0 ] = static_cast< std::uint8_t >( details::sm_opcodes::pairing_random );\n        std::copy( nonce.begin(), nonce.end(), &output[ 1 ] );\n    }\n\n    template < typename SecurityFunctions, template < class OtherConnectionData > class ConnectionData, typename ... Options >\n    template < class Connection >\n    void details::security_manager_base< SecurityFunctions, ConnectionData, Options... >::lesc_handle_pairing_dhkey_check( const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size, Connection& state )\n    {\n        if ( in_size != pairing_dhkey_check_size )\n            return this->error_response( details::sm_error_codes::invalid_parameters, output, out_size, state );\n\n        static const auto expected_states = {\n            details::sm_pairing_state::lesc_pairing_random_exchanged,\n            details::sm_pairing_state::user_response_wait,\n            details::sm_pairing_state::user_response_failed,\n            details::sm_pairing_state::user_response_success\n        };\n\n        if ( std::find( std::begin( expected_states ), std::end( expected_states ), state.state() ) == std::end( expected_states ) )\n            return this->error_response( details::sm_error_codes::unspecified_reason, output, out_size, state );\n\n        if ( state.state() == details::sm_pairing_state::user_response_wait )\n        {\n            out_size = 0;\n        }\n        else if ( state.state() == details::sm_pairing_state::user_response_failed )\n        {\n            return this->error_response( details::sm_error_codes::passkey_entry_failed, output, out_size, state );\n        }\n        else\n        {\n            const details::ecdh_shared_secret_t dh_key = security_functions().p256( state.local_private_key(), state.remote_public_key() );\n\n            details::uint128_t mac_key;\n            details::uint128_t ltk;\n            static const details::uint128_t zero = {{ 0 }};\n\n            std::tie( mac_key, ltk ) = security_functions().f5( dh_key, state.remote_nonce(), state.local_nonce(), state.remote_address(), security_functions().local_address() );\n\n            const auto calc_ea = security_functions().f6( mac_key, state.remote_nonce(), state.local_nonce(), zero, state.remote_io_caps(), state.remote_address(), security_functions().local_address() );\n\n            if ( !std::equal( calc_ea.begin(), calc_ea.end(), &input[ 1 ] ) )\n                return this->error_response( details::sm_error_codes::dhkey_check_failed, output, out_size, state );\n\n            const auto eb = security_functions().f6( mac_key, state.local_nonce(), state.remote_nonce(), zero, lesc_local_io_caps(), security_functions().local_address(), state.remote_address() );\n\n            out_size = pairing_dhkey_check_size;\n            output[ 0 ] = static_cast< std::uint8_t >( details::sm_opcodes::pairing_dhkey_check );\n            std::copy( eb.begin(), eb.end(), &output[ 1 ] );\n\n            state.lesc_pairing_completed( ltk );\n            state.store_lesc_key_in_bond_db( ltk, state );\n        }\n    }\n\n    template < typename SecurityFunctions, template < class OtherConnectionData > class ConnectionData, typename ... Options >\n    template < class Connection >\n    bool details::security_manager_base< SecurityFunctions, ConnectionData, Options... >::lesc_security_manager_output_available( Connection& state ) const\n    {\n        return state.state() == details::sm_pairing_state::lesc_public_keys_exchanged\n            || state.state() == details::sm_pairing_state::user_response_success\n            || state.state() == details::sm_pairing_state::user_response_failed;\n    }\n\n    template < typename SecurityFunctions, template < class OtherConnectionData > class ConnectionData, typename ... Options >\n    template < class Connection >\n    void details::security_manager_base< SecurityFunctions, ConnectionData, Options... >::lesc_l2cap_output( std::uint8_t* output, std::size_t& out_size, Connection& state )\n    {\n        assert( lesc_security_manager_output_available( state ) );\n\n        if ( state.state() == details::sm_pairing_state::lesc_public_keys_exchanged )\n        {\n            const auto& Nb = state.local_nonce();\n            const std::uint8_t* Pkax = state.remote_public_key_x();\n            const std::uint8_t* PKbx = state.local_public_key_x();\n\n            const auto confirm = security_functions().f4( PKbx, Pkax, Nb, 0 );\n\n            out_size = this->pairing_confirm_size;\n            output[ 0 ] = static_cast< std::uint8_t >( details::sm_opcodes::pairing_confirm );\n            std::copy( confirm.begin(), confirm.end(), &output[ 1 ] );\n\n            state.pairing_confirm_send();\n        }\n        else if ( state.state() == details::sm_pairing_state::user_response_success )\n        {\n            const details::ecdh_shared_secret_t dh_key = security_functions().p256( state.local_private_key(), state.remote_public_key() );\n\n            details::uint128_t mac_key;\n            details::uint128_t ltk;\n            static const details::uint128_t zero = {{ 0 }};\n\n            std::tie( mac_key, ltk ) = security_functions().f5( dh_key, state.remote_nonce(), state.local_nonce(), state.remote_address(), security_functions().local_address() );\n            const auto eb = security_functions().f6( mac_key, state.local_nonce(), state.remote_nonce(), zero, this->lesc_local_io_caps(), security_functions().local_address(), state.remote_address() );\n\n            out_size = this->pairing_dhkey_check_size;\n            output[ 0 ] = static_cast< std::uint8_t >( details::sm_opcodes::pairing_dhkey_check );\n            std::copy( eb.begin(), eb.end(), &output[ 1 ] );\n\n            state.lesc_pairing_completed( ltk );\n            state.store_lesc_key_in_bond_db( ltk, state );\n        }\n        else\n        {\n            this->error_response( details::sm_error_codes::passkey_entry_failed, output, out_size, state );\n        }\n\n    }\n\n    template < typename SecurityFunctions, template < class OtherConnectionData > class ConnectionData, typename ... Options >\n    details::lesc_pairing_algorithm details::security_manager_base< SecurityFunctions, ConnectionData, Options... >::lesc_select_pairing_algorithm( std::uint8_t io_capability, std::uint8_t oob_data_flag, std::uint8_t /* auth_req */, bool has_oob_data )\n    {\n        if ( oob_data_flag || has_oob_data )\n            return details::lesc_pairing_algorithm::oob_authentication;\n\n        return io_device_t::select_lesc_pairing_algorithm( io_capability );\n    }\n\n    // Legacy\n    template < typename SecurityFunctions, template < class OtherConnectionData > class ConnectionData, typename ... Options >\n    template < class Connection >\n    void details::legacy_security_manager_impl< SecurityFunctions, ConnectionData, Options... >::l2cap_input(\n        const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size, Connection& state )\n    {\n        using namespace bluetoe::details;\n\n        // is there at least an opcode?\n        if ( in_size == 0 )\n            return this->error_response( sm_error_codes::invalid_parameters, output, out_size, state );\n\n        assert( in_size != 0 );\n        assert( out_size >= default_att_mtu_size );\n\n        const sm_opcodes opcode = static_cast< sm_opcodes >( input[ 0 ] );\n\n        switch ( opcode )\n        {\n            case sm_opcodes::pairing_request:\n                this->legacy_handle_pairing_request( input, in_size, output, out_size, state );\n                break;\n            case sm_opcodes::pairing_confirm:\n                this->legacy_handle_pairing_confirm( input, in_size, output, out_size, state );\n                break;\n            case sm_opcodes::pairing_random:\n                this->legacy_handle_pairing_random( input, in_size, output, out_size, state );\n                break;\n            default:\n                this->error_response( sm_error_codes::command_not_supported, output, out_size, state );\n        }\n    }\n\n    template < typename SecurityFunctions, template < class OtherConnectionData > class ConnectionData, typename ... Options >\n    template < class Connection >\n    void details::legacy_security_manager_impl< SecurityFunctions, ConnectionData, Options... >::l2cap_output( std::uint8_t* output, std::size_t& out_size, Connection& state )\n    {\n        state.distribute_keys( output, out_size, state );\n    }\n\n    // LESC\n    template < typename SecurityFunctions, template < class OtherConnectionData > class ConnectionData, typename ... Options >\n    template < class Connection >\n    void details::lesc_security_manager_impl< SecurityFunctions, ConnectionData, Options... >::l2cap_input(\n        const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size, Connection& state )\n    {\n        using namespace bluetoe::details;\n\n        // is there at least an opcode?\n        if ( in_size == 0 )\n            return this->error_response( sm_error_codes::invalid_parameters, output, out_size, state );\n\n        assert( in_size != 0 );\n        assert( out_size >= default_att_mtu_size );\n\n        const sm_opcodes opcode = static_cast< sm_opcodes >( input[ 0 ] );\n\n        switch ( opcode )\n        {\n            case sm_opcodes::pairing_request:\n                this->lesc_handle_pairing_request( input, in_size, output, out_size, state );\n                break;\n            case sm_opcodes::pairing_public_key:\n                this->lesc_handle_pairing_public_key( input, in_size, output, out_size, state );\n                break;\n            case sm_opcodes::pairing_random:\n                this->lesc_handle_pairing_random( input, in_size, output, out_size, state );\n                break;\n            case sm_opcodes::pairing_dhkey_check:\n                this->lesc_handle_pairing_dhkey_check( input, in_size, output, out_size, state );\n                break;\n            default:\n                this->error_response( sm_error_codes::command_not_supported, output, out_size, state );\n        }\n    }\n\n    template < typename SecurityFunctions, template < class OtherConnectionData > class ConnectionData, typename ... Options >\n    template < class Connection >\n    void details::lesc_security_manager_impl< SecurityFunctions, ConnectionData, Options... >::l2cap_output( std::uint8_t* output, std::size_t& out_size, Connection& state )\n    {\n        if ( this->lesc_security_manager_output_available( state ) )\n        {\n            this->lesc_l2cap_output( output, out_size, state );\n        }\n        else\n        {\n            out_size = 0;\n        }\n    }\n\n    // security_manager_impl\n    template < typename SecurityFunctions, template < class OtherConnectionData > class ConnectionData, typename ... Options >\n    template < class Connection >\n    void details::security_manager_impl< SecurityFunctions, ConnectionData, Options... >::l2cap_input( const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size, Connection& state )\n    {\n        using namespace bluetoe::details;\n\n        // is there at least an opcode?\n        if ( in_size == 0 )\n            return this->error_response( sm_error_codes::invalid_parameters, output, out_size, state );\n\n        assert( in_size != 0 );\n        assert( out_size >= default_att_mtu_size );\n\n        const sm_opcodes opcode = static_cast< sm_opcodes >( input[ 0 ] );\n\n        switch ( opcode )\n        {\n            case sm_opcodes::pairing_request:\n                handle_pairing_request( input, in_size, output, out_size, state );\n                break;\n            case sm_opcodes::pairing_confirm:\n                this->legacy_handle_pairing_confirm( input, in_size, output, out_size, state );\n                break;\n            case sm_opcodes::pairing_random:\n                if ( state.state() == sm_pairing_state::legacy_pairing_confirmed )\n                {\n                    this->legacy_handle_pairing_random( input, in_size, output, out_size, state );\n                }\n                else\n                {\n                    this->lesc_handle_pairing_random( input, in_size, output, out_size, state );\n                }\n                break;\n            case sm_opcodes::pairing_public_key:\n                this->lesc_handle_pairing_public_key( input, in_size, output, out_size, state );\n                break;\n            case sm_opcodes::pairing_dhkey_check:\n                this->lesc_handle_pairing_dhkey_check( input, in_size, output, out_size, state );\n                break;\n            default:\n                this->error_response( sm_error_codes::command_not_supported, output, out_size, state );\n        }\n    }\n\n    template < typename SecurityFunctions, template < class OtherConnectionData > class ConnectionData, typename ... Options >\n    template < class Connection >\n    void details::security_manager_impl< SecurityFunctions, ConnectionData, Options... >::l2cap_output( std::uint8_t* output, std::size_t& out_size, Connection& state )\n    {\n        if ( this->lesc_security_manager_output_available( state ) )\n        {\n            this->lesc_l2cap_output( output, out_size, state );\n        }\n        else\n        {\n            state.distribute_keys( output, out_size, state );\n        }\n    }\n\n    template < typename SecurityFunctions, template < class OtherConnectionData > class ConnectionData, typename ... Options >\n    template < class Connection >\n    void details::security_manager_impl< SecurityFunctions, ConnectionData, Options... >::handle_pairing_request( const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size, Connection& state )\n    {\n        using namespace details;\n\n        if ( in_size != this->pairing_req_resp_size )\n            return this->error_response( sm_error_codes::invalid_parameters, output, out_size, state );\n\n        if ( state.state() != details::sm_pairing_state::idle )\n            return this->error_response( sm_error_codes::unspecified_reason, output, out_size, state );\n\n        const std::uint8_t io_capability                = input[ 1 ];\n        const std::uint8_t oob_data_flag                = input[ 2 ];\n        const std::uint8_t auth_req                     = input[ 3 ];\n        const std::uint8_t max_key_size                 = input[ 4 ];\n        const std::uint8_t initiator_key_distribution   = input[ 5 ];\n        const std::uint8_t responder_key_distribution   = input[ 6 ];\n\n        if (\n            ( io_capability > static_cast< std::uint8_t >( io_capabilities::last ) )\n         || ( oob_data_flag & ~0x01 )\n         || ( max_key_size < this->min_max_key_size || max_key_size > this->max_max_key_size )\n         || ( initiator_key_distribution & 0xf0 )\n         || ( responder_key_distribution & 0xf0 )\n        )\n        {\n            return this->error_response( sm_error_codes::invalid_parameters, output, out_size, state );\n        }\n\n        this->request_oob_data_presents_for_remote_device( state.remote_address() );\n\n        const bool lesc_pairing = ( auth_req & static_cast< std::uint8_t >(authentication_requirements_flags::secure_connections ) );\n\n        if ( lesc_pairing )\n        {\n            const io_capabilities_t remote_io_caps = {{ io_capability, oob_data_flag, auth_req }};\n            state.pairing_algorithm( this->lesc_select_pairing_algorithm( io_capability, oob_data_flag, auth_req, this->has_oob_data_for_remote_device() ) );\n            state.pairing_requested( remote_io_caps );\n\n            this->create_pairing_response( output, out_size, this->lesc_local_io_caps() );\n        }\n        else\n        {\n            state.pairing_algorithm( this->legacy_select_pairing_algorithm( io_capability, oob_data_flag, auth_req, this->has_oob_data_for_remote_device() ) );\n\n            this->create_pairing_response( output, out_size, this->lesc_local_io_caps() );\n\n            const details::uint128_t srand    = security_functions().create_srand();\n            const details::uint128_t p1       = this->legacy_c1_p1( input, output, state.remote_address(), security_functions().local_address() );\n            const details::uint128_t p2       = this->legacy_c1_p2( state.remote_address(), security_functions().local_address() );\n\n            state.legacy_pairing_request( srand, p1, p2 );\n        }\n    }\n\n    // no_security_manager\n    template < typename SecurityFunctions, typename ...Os >\n    template < class Connection >\n    void no_security_manager::impl< SecurityFunctions, Os... >::l2cap_input( const std::uint8_t*, std::size_t, std::uint8_t* output, std::size_t& out_size, Connection& )\n    {\n        error_response( details::sm_error_codes::pairing_not_supported, output, out_size );\n    }\n\n    template < typename SecurityFunctions, typename ...Os >\n    template < class Connection >\n    void no_security_manager::impl< SecurityFunctions, Os... >::l2cap_output( std::uint8_t*, std::size_t& out_size, Connection& )\n    {\n        out_size = 0;\n    }\n    /** @endcond */\n}\n\n#endif // include guard\n"
  },
  {
    "path": "bluetoe/utility/CMakeLists.txt",
    "content": "add_library(bluetoe_utility STATIC\n            address.cpp)\nadd_library(bluetoe::utility ALIAS bluetoe_utility)\n\ntarget_include_directories(bluetoe_utility PUBLIC include)\ntarget_compile_features(bluetoe_utility PRIVATE cxx_std_11)\ntarget_compile_options(bluetoe_utility PRIVATE -Wall -pedantic -Wextra -Wfatal-errors)\n"
  },
  {
    "path": "bluetoe/utility/address.cpp",
    "content": "#include <bluetoe/address.hpp>\n#include <cassert>\n#include <algorithm>\n#include <iterator>\n\nnamespace bluetoe {\nnamespace link_layer {\n\n    address::address()\n    {\n        std::fill( std::begin( value_ ), std::end( value_ ), 0 );\n    }\n\n    address::address( const std::initializer_list< std::uint8_t >& initial_values )\n    {\n        assert( initial_values.size() == address_size_in_bytes );\n        std::copy( initial_values.begin(), initial_values.end(), &value_[ 0 ] );\n    }\n\n    address::address( const std::uint8_t* initial_values )\n    {\n        std::copy( initial_values + 0, initial_values + address_size_in_bytes, &value_[ 0 ] );\n    }\n\n    random_device_address address::generate_static_random_address( std::uint32_t seed )\n    {\n        std::uint8_t initial_values[ address_size_in_bytes ] = {\n            static_cast<uint8_t>( seed >> 24 ),\n            static_cast<uint8_t>( seed >> 16 ),\n            static_cast<uint8_t>( seed >> 8 ),\n            static_cast<uint8_t>( seed ),\n            0x0f,\n            0xC0 };\n\n        return random_device_address( initial_values );\n    }\n\n    std::uint8_t address::msb() const\n    {\n        return value_[ address_size_in_bytes - 1 ];\n    }\n\n    bool address::operator==( const address& rhs ) const\n    {\n        return std::equal( std::begin( value_ ), std::end( value_ ), std::begin( rhs.value_ ) );\n    }\n\n    bool address::operator!=( const address& rhs ) const\n    {\n        return !( *this == rhs );\n    }\n\n    address::const_iterator address::begin() const\n    {\n        return std::begin( value_ );\n    }\n\n    address::const_iterator address::end() const\n    {\n        return std::end( value_ );\n    }\n\n    std::uint32_t address::create_prand( std::uint32_t rand )\n    {\n        rand = ( rand & 0x007fffff ) | 0x00400000;\n\n        // random part of prand should not contain only 0s or 1s\n        if ( rand == 0x007fffff || rand == 0x00400000 )\n            rand = rand ^ 0x01;\n\n        return rand;\n    }\n\n    device_address::device_address()\n        : address()\n        , is_random_( true )\n    {\n    }\n\n    bool device_address::operator==( const device_address& rhs ) const\n    {\n        return static_cast< const address& >( *this ) == rhs\n            && is_random_ == rhs.is_random_;\n    }\n\n    bool device_address::operator!=( const device_address& rhs ) const\n    {\n        return !( *this == rhs );\n    }\n\n\n}\n}\n"
  },
  {
    "path": "bluetoe/utility/include/bluetoe/address.hpp",
    "content": "#ifndef BLUETOE_LINK_LAYER_ADDRESS_HPP\n#define BLUETOE_LINK_LAYER_ADDRESS_HPP\n\n#include <cstdint>\n#include <initializer_list>\n#include <iosfwd>\n\nnamespace bluetoe {\nnamespace link_layer {\n\n    class random_device_address;\n\n    /**\n     * @brief a 48-bit universal LAN MAC address\n     */\n    class address\n    {\n    public:\n        /**\n         * @brief creates the address with all octes beeing zero (00:00:00:00:00:00)\n         */\n        address();\n\n        /**\n         * @brief initialize an address by a initializer list with exactly 6 elements\n         */\n        explicit address( const std::initializer_list< std::uint8_t >& initial_values );\n\n        /**\n         * @brief initializing an address by taking 6 bytes from the given start of an array\n         */\n        explicit address( const std::uint8_t* initial_values );\n\n        /**\n         * @brief generates a valid static random address out of a given seed value\n         *\n         * The function generates a random device address that is valid and that has always\n         * the same value for the same seed.\n         */\n        static random_device_address generate_static_random_address( std::uint32_t seed );\n\n        /**\n         * @brief generates a resolvable private address\n         */\n        template < typename HashFunc >\n        static random_device_address generate_resolvable_private_address( const std::uint8_t* irk, std::uint32_t random, HashFunc hash_func );\n\n        /**\n         * @brief prints this in a human readable manner\n         */\n        std::ostream& print( std::ostream& ) const;\n\n        /**\n         * @brief returns the most significant byte of the address\n         */\n        std::uint8_t msb() const;\n\n        /**\n         * @brief returns true, if this address is the same as the rhs address\n         */\n        bool operator==( const address& rhs ) const;\n\n        /**\n         * @brief returns false, if this address is the same as the rhs address\n         */\n        bool operator!=( const address& rhs ) const;\n\n        /**\n         * @brief random access iterator\n         */\n        typedef std::uint8_t const * const_iterator;\n\n        /**\n         * @brief returns an iterator to the first byte (LSB) of the address\n         */\n        const_iterator begin() const;\n\n        /**\n         * @brief returns an iterator one behind the last byte of the address\n         */\n        const_iterator end() const;\n    private:\n        static std::uint32_t create_prand( std::uint32_t rand );\n\n        static constexpr std::size_t address_size_in_bytes = 6;\n        std::uint8_t value_[ address_size_in_bytes ];\n\n        // this type is not intended for polymorphic use; not implemented\n        void operator delete  ( void* ptr );\n        void operator delete[]( void* ptr );\n    };\n\n    /**\n     * @brief prints the given address in a human readable manner\n     */\n    std::ostream& operator<<( std::ostream& out, const address& a );\n\n    /**\n     * @brief data type containing a device address and the address type\n     *        (public or random).\n     *\n     * A device address can either be a public or a random device address. To\n     * construct one or the othere, use the subtypes public_device_address and\n     * random_device_address.\n     */\n    class device_address : public address\n    {\n    public:\n        device_address();\n\n        /**\n         * @brief returns true, if this device address is a random device address.\n         */\n        bool is_random() const\n        {\n            return is_random_;\n        }\n\n        /**\n         * @brief shortcut for !is_random()\n         */\n        bool is_public() const\n        {\n            return !is_random_;\n        }\n\n        /**\n         *  @brief returns true, if the given address is a static device address\n         *\n         * @pre is_random() == true\n         */\n        bool is_static() const\n        {\n            return ( *( end() - 1 ) & 0xC0 ) == 0xC0;\n        }\n\n        /**\n         * @brief returns true, if the given address is not a static device address\n         *\n         * @pre is_random() == true\n         */\n        bool is_private() const\n        {\n            const auto v = *( end() - 1 ) & 0xC0;\n            return v == 0x40 || v == 0x00;\n        }\n\n        /**\n         * @brief returns true, if the given address is private and resolvable\n         *\n         * @pre is_random() == true\n         */\n        bool is_resolvable() const\n        {\n            return ( *( end() - 1 ) & 0xC0 ) == 0x40;\n        }\n\n        /**\n         * @brief returns true, if the address is random and resolvable\n         */\n        bool is_random_resolvable() const\n        {\n            return is_random() && is_resolvable();\n        }\n\n        using address::operator==;\n        using address::operator!=;\n\n        /**\n         * @brief returns true, if this device address is the same as the rhs device address\n         */\n        bool operator==( const device_address& rhs ) const;\n\n        /**\n         * @brief returns false, if this device address is the same as the rhs device address\n         */\n        bool operator!=( const device_address& rhs ) const;\n\n        /**\n         * @brief initialize an address by a initializer list with exactly 6 elements and a flag\n         *        indicating whether this address is a random address or not.\n         */\n        device_address( const std::initializer_list< std::uint8_t >& initial_values, bool is_random )\n            : address( initial_values )\n            , is_random_( is_random )\n        {}\n\n        /**\n         * @brief initializing an address by taking 6 bytes from the given start of an array and a flag\n         *        indicating whether this address is a random address or not.\n         */\n        device_address( const std::uint8_t* initial_values, bool is_random )\n            : address( initial_values )\n            , is_random_( is_random )\n        {}\n\n    protected:\n        /**\n         * @brief constructs a public or random default device address (00:00:00:00:00:00)\n         */\n        explicit device_address( bool is_random )\n            : address()\n            , is_random_( is_random )\n        {}\n\n    private:\n        bool is_random_;\n    };\n\n    std::ostream& operator<<( std::ostream& out, const device_address& a );\n\n    /**\n     * @brief data type containing a public device address\n     *\n     * The type is mainly ment to be a factory to construct a device_address\n     */\n    class public_device_address : public device_address\n    {\n    public:\n        /**\n         * @brief initialize a public device address 00:00:00:00:00:00\n         */\n        public_device_address() : device_address( false ) {}\n\n        /**\n         * @brief initialize a public device address by a initializer list with exactly 6 elements\n         */\n        explicit public_device_address( const std::initializer_list< std::uint8_t >& initial_values )\n            : device_address( initial_values, false ) {}\n\n        /**\n         * @brief initializing a public device address by taking 6 bytes from the given start of an array\n         */\n        explicit public_device_address( const std::uint8_t* initial_values )\n            : device_address( initial_values, false ) {}\n    };\n\n    /**\n     * @brief data type containing a random device address\n     *\n     * The type is mainly ment to be a factory to construct a device_address\n     */\n    class random_device_address : public device_address\n    {\n    public:\n        /**\n         * @brief initialize a random device address 00:00:00:00:00:00\n         */\n        random_device_address() : device_address( true ) {}\n\n        /**\n         * @brief initialize a random device address by a initializer list with exactly 6 elements\n         */\n        explicit random_device_address( const std::initializer_list< std::uint8_t >& initial_values )\n            : device_address( initial_values, true ) {}\n\n        /**\n         * @brief initializing a random device address by taking 6 bytes from the given start of an array\n         */\n        explicit random_device_address( const std::uint8_t* initial_values )\n            : device_address( initial_values, true ) {}\n    };\n\n    template < typename HashFunc >\n    random_device_address address::generate_resolvable_private_address( const std::uint8_t* irk, std::uint32_t random, HashFunc hash_func )\n    {\n        const std::uint32_t prand = create_prand( random );\n        const std::uint32_t hash = hash_func( irk, prand );\n\n        std::uint8_t initial_values[ address_size_in_bytes ] = {\n            static_cast<uint8_t>( prand >> 16 ),\n            static_cast<uint8_t>( prand >> 8 ),\n            static_cast<uint8_t>( prand ),\n            static_cast<uint8_t>( hash >> 16 ),\n            static_cast<uint8_t>( hash >> 8 ),\n            static_cast<uint8_t>( hash ) };\n\n        return random_device_address( initial_values );\n    }\n\n}\n\n}\n\n#endif"
  },
  {
    "path": "bluetoe/utility/include/bluetoe/attribute.hpp",
    "content": "#ifndef BLUETOE_ATTRIBUTE_HPP\n#define BLUETOE_ATTRIBUTE_HPP\n\n#include <bluetoe/meta_tools.hpp>\n#include <bluetoe/client_characteristic_configuration.hpp>\n#include <bluetoe/pairing_status.hpp>\n#include <bluetoe/attribute_handle.hpp>\n\n#include <cstdint>\n#include <cstddef>\n#include <cassert>\n\nnamespace bluetoe {\nnamespace details {\n\n    /*\n     * Attribute and accessing an attribute\n     */\n\n    enum class attribute_access_result : std::int_fast16_t {\n        // Accessing the attribute was successfully\n        success                         = 0x00,\n\n        // here goes the ATT return codes\n        invalid_offset                  = 0x07,\n        write_not_permitted             = 0x03,\n        read_not_permitted              = 0x02,\n        invalid_attribute_value_length  = 0x0d,\n        attribute_not_long              = 0x0b,\n        request_not_supported           = 0x06,\n        insufficient_encryption         = 0x0f,\n        insufficient_authentication     = 0x05,\n\n        // returned when access type is compare_128bit_uuid and the attribute contains a 128bit uuid and\n        // the buffer in attribute_access_arguments is equal to the contained uuid.\n        uuid_equal                      = 0x100,\n        value_equal\n    };\n\n    enum class attribute_access_type {\n        read,\n        write,\n        compare_128bit_uuid,\n        compare_value\n    };\n\n    struct attribute_access_arguments\n    {\n        attribute_access_type               type;\n        std::uint8_t*                       buffer;\n        std::size_t                         buffer_size;\n        std::size_t                         buffer_offset;\n        client_characteristic_configuration client_config;\n        connection_security_attributes      connection_security;\n        void*                               server;\n\n        template < std::size_t N >\n        static constexpr attribute_access_arguments read(\n            std::uint8_t(&buffer)[N],\n            std::size_t offset,\n            const client_characteristic_configuration& cc = client_characteristic_configuration(),\n            const connection_security_attributes& cs = connection_security_attributes() )\n        {\n            return attribute_access_arguments{\n                attribute_access_type::read,\n                &buffer[ 0 ],\n                N,\n                offset,\n                cc,\n                cs,\n                nullptr\n            };\n        }\n\n        static attribute_access_arguments read(\n            std::uint8_t* begin, std::uint8_t* end, std::size_t offset,\n            const client_characteristic_configuration& cc,\n            const connection_security_attributes& cs,\n            void* server )\n        {\n            assert( end >= begin );\n\n            return attribute_access_arguments{\n                attribute_access_type::read,\n                begin,\n                static_cast< std::size_t >( end - begin ),\n                offset,\n                cc,\n                cs,\n                server\n            };\n        }\n\n        template < std::size_t N >\n        static constexpr attribute_access_arguments write( const std::uint8_t(&buffer)[N], std::size_t offset = 0,\n            const client_characteristic_configuration& cc = client_characteristic_configuration(),\n            const connection_security_attributes& cs = connection_security_attributes() )\n        {\n            return attribute_access_arguments{\n                attribute_access_type::write,\n                const_cast< std::uint8_t* >( &buffer[ 0 ] ),\n                N,\n                offset,\n                cc,\n                cs,\n                nullptr\n            };\n        }\n\n        static attribute_access_arguments write( const std::uint8_t* begin, const std::uint8_t* end, std::size_t offset,\n            const client_characteristic_configuration& cc,\n            const connection_security_attributes& cs,\n            void* server )\n        {\n            assert( end >= begin );\n\n            return attribute_access_arguments{\n                attribute_access_type::write,\n                const_cast< std::uint8_t* >( begin ),\n                static_cast< std::size_t >( end - begin ),\n                offset,\n                cc,\n                cs,\n                server\n            };\n        }\n\n        static constexpr attribute_access_arguments check_write( void* server )\n        {\n            return attribute_access_arguments{\n                attribute_access_type::write,\n                0,\n                0,\n                0,\n                client_characteristic_configuration(),\n                connection_security_attributes(),\n                server\n            };\n        }\n\n        static constexpr attribute_access_arguments compare_128bit_uuid( const std::uint8_t* uuid )\n        {\n            return attribute_access_arguments{\n                attribute_access_type::compare_128bit_uuid,\n                const_cast< std::uint8_t* >( uuid ),\n                16u,\n                0,\n                client_characteristic_configuration(),\n                connection_security_attributes(),\n                nullptr\n            };\n        }\n\n        static attribute_access_arguments compare_value( const std::uint8_t* begin, const std::uint8_t* end, void* )\n        {\n            assert( end >= begin );\n\n            return attribute_access_arguments{\n                attribute_access_type::compare_value,\n                const_cast< std::uint8_t* >( begin ),\n                static_cast< std::size_t >( end - begin ),\n                0,\n                client_characteristic_configuration(),\n                connection_security_attributes(),\n                nullptr\n            };\n        }\n    };\n\n    typedef attribute_access_result ( *attribute_access )( attribute_access_arguments&, std::size_t attribute_index );\n\n    /*\n     * An attribute is an uuid combined with a mean of how to access the attributes\n     *\n     * design decisions to _not_ use pointer to staticaly allocated virtual objects:\n     * - makeing access a pointer to a virtual base class would result in storing a pointer that points to a pointer (vtable) to list with a bunch of functions.\n     * - it's most likely that most attributes will not have any mutable data.\n     * attribute contains only one function that takes a attribute_access_type to save memory and in the expectation that there are only a few different combination of\n     * access functions.\n     */\n    struct attribute {\n        // all uuids used by GATT are 16 bit UUIDs (except for Characteristic Value Declaration for which the value internal_128bit_uuid is used, if the UUID is 128bit long)\n        std::uint16_t       uuid;\n        attribute_access    access;\n    };\n\n    /*\n     * Given that T is a tuple with elements that implement attribute_at< std::size_t, Service >() and number_of_attributes, the type implements\n     * attribute_at() for a list of attribute lists.\n     */\n    template < typename T, typename CCCDIndices, std::size_t ClientCharacteristicIndex, typename Service, typename Server >\n    struct attribute_at_list;\n\n    template < typename CCCDIndices, std::size_t ClientCharacteristicIndex, typename Service, typename Server >\n    struct attribute_at_list< std::tuple<>, CCCDIndices, ClientCharacteristicIndex, Service, Server >\n    {\n        static details::attribute attribute_at( std::size_t )\n        {\n            assert( !\"index out of bound\" );\n            return details::attribute();\n        }\n    };\n\n    template <\n        typename T,\n        typename ...Ts,\n        typename CCCDIndices,\n        std::size_t ClientCharacteristicIndex,\n        typename Service,\n        typename Server >\n    struct attribute_at_list< std::tuple< T, Ts... >, CCCDIndices, ClientCharacteristicIndex, Service, Server >\n    {\n        static details::attribute attribute_at( std::size_t index )\n        {\n            if ( index < T::number_of_attributes )\n                return T::template attribute_at< CCCDIndices, ClientCharacteristicIndex, Service, Server >( index );\n\n            typedef details::attribute_at_list< std::tuple< Ts... >, CCCDIndices, ClientCharacteristicIndex + T::number_of_client_configs, Service, Server > remaining_characteristics;\n\n            return remaining_characteristics::attribute_at( index - T::number_of_attributes );\n        }\n    };\n\n    /*\n     * Iterating the list of services is the same, but needs less parameters\n     */\n    template < typename Services, typename Server, typename CCCDIndices, std::size_t ClientCharacteristicIndex = 0, typename AllServices = Services >\n    struct attribute_from_service_list;\n\n    template < typename Server, typename CCCDIndices, std::size_t ClientCharacteristicIndex, typename AllServices >\n    struct attribute_from_service_list< std::tuple<>, Server, CCCDIndices, ClientCharacteristicIndex, AllServices >\n    {\n        static details::attribute attribute_at( std::size_t )\n        {\n            assert( !\"index out of bound\" );\n            return details::attribute();\n        }\n    };\n\n    template <\n        typename T,\n        typename ...Ts,\n        typename Server,\n        typename CCCDIndices,\n        std::size_t ClientCharacteristicIndex,\n        typename AllServices >\n    struct attribute_from_service_list< std::tuple< T, Ts... >, Server, CCCDIndices, ClientCharacteristicIndex, AllServices >\n    {\n        static details::attribute attribute_at( std::size_t index )\n        {\n            if ( index < T::number_of_attributes )\n                return T::template attribute_at< CCCDIndices, ClientCharacteristicIndex, AllServices, Server >( index );\n\n            typedef details::attribute_from_service_list<\n                std::tuple< Ts... >,\n                Server,\n                CCCDIndices,\n                ClientCharacteristicIndex + T::number_of_client_configs,\n                AllServices > remaining_characteristics;\n\n            return remaining_characteristics::attribute_at( index - T::number_of_attributes );\n        }\n    };\n\n    /**\n     * @brief type of notification information to be communicated between ATT and link layer\n     */\n    enum class notification_type {\n        notification,\n        indication,\n        confirmation\n    };\n\n    /**\n     * @brief data needed to send an indication or notification to the l2cap layer\n     */\n    class notification_data\n    {\n    public:\n        notification_data()\n            : attribute_table_index_( details::invalid_attribute_index )\n            , client_characteristic_configuration_index_( 0 )\n        {\n            assert( !valid() );\n        }\n\n        notification_data( std::size_t value_attribute_index, std::size_t client_characteristic_configuration_index )\n            : attribute_table_index_( value_attribute_index )\n            , client_characteristic_configuration_index_( client_characteristic_configuration_index )\n        {\n            assert( valid() );\n        }\n\n        bool valid() const\n        {\n            return attribute_table_index_ != details::invalid_attribute_index;\n        }\n\n        /**\n         * @brief The index of the value attribute in the nofied characteristic\n         */\n        std::size_t attribute_table_index() const\n        {\n            return attribute_table_index_;\n        }\n\n        /**\n         * @brief index into the client characteristic configuration\n         */\n        std::size_t client_characteristic_configuration_index() const\n        {\n            return client_characteristic_configuration_index_;\n        }\n\n        /*\n         * For testing\n         */\n        void clear()\n        {\n            attribute_table_index_ = details::invalid_attribute_index;\n            client_characteristic_configuration_index_ = 0;\n        }\n\n    private:\n        std::size_t     attribute_table_index_;\n        std::size_t     client_characteristic_configuration_index_;\n    };\n\n    /*\n     * Given a list of characteristics, find the data required for notification\n     */\n    template < typename CharacteristicList, typename UUID >\n    struct find_characteristic_data_by_uuid_in_characteristic_list;\n\n    template < typename UUID >\n    struct find_characteristic_data_by_uuid_in_characteristic_list< std::tuple<>, UUID >\n    {\n        typedef details::no_such_type type;\n    };\n\n    template <\n        typename Characteristic,\n        typename ... Characteristics,\n        typename UUID >\n    struct find_characteristic_data_by_uuid_in_characteristic_list< std::tuple< Characteristic, Characteristics...>, UUID >\n    {\n        using found = std::is_same< typename Characteristic::configured_uuid, UUID >;\n\n        using next = typename find_characteristic_data_by_uuid_in_characteristic_list<\n            std::tuple< Characteristics... >,\n            UUID >::type;\n\n        struct result\n        {\n            static constexpr bool has_indication   = Characteristic::value_type::has_indication;\n            static constexpr bool has_notification = Characteristic::value_type::has_notification;\n            using characteristic_t = Characteristic;\n        };\n\n        typedef typename details::select_type<\n            found::value,\n            result,\n            next\n        >::type type;\n    };\n\n    /*\n     * Given a list of services and a UUID, find the data required for notification\n     */\n    template < typename ServiceList, typename UUID >\n    struct find_characteristic_data_by_uuid_in_service_list;\n\n    template < typename UUID >\n    struct find_characteristic_data_by_uuid_in_service_list< std::tuple<>, UUID >\n    {\n        typedef details::no_such_type type;\n    };\n\n    struct wrap_search_in_service_list {\n        template <\n            typename UUID,\n            typename ... Services >\n        using f = typename find_characteristic_data_by_uuid_in_service_list<\n            std::tuple< Services... >, UUID >::type;\n    };\n\n    template < typename Result >\n    struct wrap_result_found_in_service {\n        template <\n            typename UUID,\n            typename ... Services >\n        using f = Result;\n    };\n\n    template <\n        typename Service,\n        typename ... Services,\n        typename UUID >\n    struct find_characteristic_data_by_uuid_in_service_list< std::tuple< Service, Services...>, UUID >\n    {\n        // The searched UUID is either in first Service or in the remaining service. There is no point in searching through\n        // the remaining service, if the first service contains the characteristic already\n        using c_type = typename find_characteristic_data_by_uuid_in_characteristic_list<\n            typename Service::characteristics, UUID >::type;\n\n        using next_path =\n            typename select_type<\n                std::is_same< c_type, no_such_type  >::value,\n                wrap_search_in_service_list,\n                wrap_result_found_in_service< c_type >\n            >::type;\n\n        using type = typename next_path::template f<\n            UUID,\n            Services... >;\n    };\n\n\n    inline attribute_access_result attribute_value_read_access( attribute_access_arguments& args, const std::uint8_t* memory, std::size_t size )\n    {\n        if ( args.type == attribute_access_type::compare_value )\n        {\n            return size == args.buffer_size && std::equal( memory, memory + size, args.buffer )\n                ? attribute_access_result::value_equal\n                : attribute_access_result::read_not_permitted;\n        }\n\n        if ( args.buffer_offset > size )\n            return details::attribute_access_result::invalid_offset;\n\n        args.buffer_size = std::min< std::size_t >( args.buffer_size, size - args.buffer_offset );\n        const std::uint8_t* const ptr = memory + args.buffer_offset;\n\n        std::copy( ptr, ptr + args.buffer_size, args.buffer );\n\n        return details::attribute_access_result::success;\n    }\n\n    inline attribute_access_result attribute_value_read_only_access( attribute_access_arguments& args, const std::uint8_t* memory, std::size_t size )\n    {\n        if ( args.type != attribute_access_type::read && args.type != attribute_access_type::compare_value )\n            return attribute_access_result::write_not_permitted;\n\n        return attribute_value_read_access( args, memory, size );\n    }\n\n}\n}\n\n#endif\n"
  },
  {
    "path": "bluetoe/utility/include/bluetoe/bits.hpp",
    "content": "#ifndef BLUETOE_BITS_HPP\n#define BLUETOE_BITS_HPP\n\n#include <cstdint>\n#include <type_traits>\n\nnamespace bluetoe {\nnamespace details {\n\n    constexpr std::uint16_t read_handle( const std::uint8_t* h )\n    {\n        return *h + ( *( h + 1 ) << 8 );\n    }\n\n    constexpr std::uint16_t read_16bit_uuid( const std::uint8_t* h )\n    {\n        return read_handle( h );\n    }\n\n    constexpr std::uint16_t read_16bit( const std::uint8_t* h )\n    {\n        return read_handle( h );\n    }\n\n    constexpr std::uint32_t read_24bit( const std::uint8_t* h )\n    {\n        return static_cast< std::uint32_t >( read_16bit( h ) ) | ( static_cast< std::uint32_t >( *( h + 2 ) ) << 16 );\n    }\n\n    constexpr std::uint32_t read_32bit( const std::uint8_t* p )\n    {\n        return static_cast< std::uint32_t >( read_16bit( p ) )\n             | ( static_cast< std::uint32_t >( read_16bit( p + 2 ) ) << 16 );\n    }\n\n    constexpr std::uint64_t read_64bit( const std::uint8_t* p )\n    {\n        return static_cast< std::uint64_t >( read_32bit( p ) )\n             | ( static_cast< std::uint64_t >( read_32bit( p + 4 ) ) << 32 );\n    }\n\n    inline std::uint8_t* write_handle( std::uint8_t* out, std::uint16_t handle )\n    {\n        out[ 0 ] = handle & 0xff;\n        out[ 1 ] = handle >> 8;\n\n        return out + 2;\n    }\n\n    inline std::uint8_t* write_16bit_uuid( std::uint8_t* out, std::uint16_t uuid )\n    {\n        return write_handle( out, uuid );\n    }\n\n    inline std::uint8_t* write_16bit( std::uint8_t* out, std::uint16_t bits16 )\n    {\n        return write_handle( out, bits16 );\n    }\n\n    inline std::uint8_t* write_32bit( std::uint8_t* out, std::uint32_t bits32 )\n    {\n        return write_16bit( write_16bit( out, bits32 & 0xffff ), bits32 >> 16 );\n    }\n\n    inline std::uint8_t* write_64bit( std::uint8_t* out, std::uint64_t bits64 )\n    {\n        return write_32bit( write_32bit( out, bits64 & 0xffffffff ), bits64 >> 32 );\n    }\n\n    inline std::uint8_t* write_byte( std::uint8_t* out, std::uint8_t byte )\n    {\n        *out = byte;\n        return out + 1;\n    }\n\n    /**\n     * @brief given two unsigned integers returning the absolute minimum distance between\n     *        both, taking overflow into account.\n     *\n     * Starting at start, incrementing start as until start reached end, would result in a\n     * positiv result. Decrementing start till it reaches end, would result in a negative\n     * result. The function will return the absolute smaller value of both.\n     */\n    template < typename I >\n    typename std::make_signed< I >::type distance( I start, I end )\n    {\n        static_assert( std::is_unsigned< I >::value, \"I has to be an unsigned type\" );\n\n        if ( start > end )\n            return -distance( end, start );\n\n        const I positive = end - start;\n        const I negative = start + ~I(0) - end + 1;\n\n        return positive < negative\n            ? positive\n            : -negative;\n    }\n\n    template < std::size_t N, typename I >\n    typename std::make_signed< I >::type distance_n( I start, I end )\n    {\n        static_assert( std::is_unsigned< I >::value, \"I has to be an unsigned type\" );\n\n        if ( start > end )\n            return -distance_n< N >( end, start );\n\n        const I positive = end - start;\n        const I negative = start + I(1 << N) - end;\n\n        return positive < negative\n            ? positive\n            : -negative;\n    }\n}\n}\n#endif\n"
  },
  {
    "path": "bluetoe/utility/include/bluetoe/client_characteristic_configuration.hpp",
    "content": "#ifndef BLUETOE_CLIENT_CHARACTERISTIC_CONFIGURATION_HPP\n#define BLUETOE_CLIENT_CHARACTERISTIC_CONFIGURATION_HPP\n\n#include <cassert>\n#include <cstdint>\n#include <algorithm>\n\nnamespace bluetoe {\nnamespace details {\n\n    /**\n     * @brief somehow stronger typed pointer to the beginning of the array where client configurations are stored.\n     *\n     * In opposite to client_characteristic_configurations<>, this class is not a template.\n     */\n    class client_characteristic_configuration\n    {\n    public:\n        constexpr client_characteristic_configuration()\n            : data_( nullptr )\n        {\n        }\n\n        constexpr explicit client_characteristic_configuration( std::uint8_t* data, std::size_t )\n            : data_( data )\n        {\n        }\n\n        std::uint16_t flags( std::size_t index ) const\n        {\n            assert( data_ );\n\n            return ( data_[ index / 4 ] >> shift( index ) ) & 0x3;\n        }\n\n        void flags( std::size_t index, std::uint16_t new_flags )\n        {\n            assert( data_ );\n\n            // do not assert on new_flags as they might come from a client\n            data_[ index / 4 ] = ( data_[ index / 4 ] & ~mask( index ) ) | ( ( new_flags & 0x03 ) << shift( index ) );\n        }\n\n        static constexpr std::size_t bits_per_config = 2;\n\n    private:\n        static constexpr std::size_t shift( std::size_t index )\n        {\n            return ( index % 4 ) * bits_per_config;\n        }\n\n        static constexpr std::uint8_t mask( std::size_t index )\n        {\n            return 0x03 << shift( index );\n        }\n\n        std::uint8_t*   data_;\n    };\n\n    /**\n     * Store for configuration and state informations for characteristics that need such informations to be\n     * stored among the connection. Such characteristics are characteristics with notification or indication\n     * beeing enabled.\n     */\n    template < std::size_t Size >\n    class client_characteristic_configurations\n    {\n    public:\n        /**\n         * This information is intendet to be used by l2cap/link layer implementations that want to\n         * add informations for characteristics with notification/indication capabilities.\n         */\n        static constexpr std::size_t number_of_characteristics_with_configuration = Size;\n\n        client_characteristic_configurations()\n        {\n            std::fill( std::begin( configs_ ), std::end( configs_ ), 0 );\n        }\n\n        client_characteristic_configuration client_configurations()\n        {\n            return client_characteristic_configuration( &configs_[ 0 ], Size );\n        };\n\n        /**\n         * @brief begin of the serialized CCCDs\n         *\n         * This can be used to store the state of the CCCDs in bonding data.\n         */\n        const std::uint8_t* serialized_cccds_begin() const\n        {\n            return std::begin( configs_ );\n        }\n\n        /**\n         * @brief end of the serialized CCCDs\n         *\n         * This can be used to store the state of the CCCDs in bonding data.\n         */\n        const std::uint8_t* serialized_cccds_end() const\n        {\n            return std::end( configs_ );\n        }\n\n        /**\n         * @brief begin of the serialized CCCDs\n         *\n         * This can be used to restores the state of the CCCDs from bonding data.\n         */\n        std::uint8_t* serialized_cccds_begin()\n        {\n            return std::begin( configs_ );\n        }\n\n        /**\n         * @brief end of the serialized CCCDs\n         *\n         * This can be used to restores the state of the CCCDs from bonding data.\n         */\n        std::uint8_t* serialized_cccds_end()\n        {\n            return std::end( configs_ );\n        }\n\n    private:\n        std::uint8_t configs_[ ( Size * client_characteristic_configuration::bits_per_config + 7 ) / 8 ];\n    };\n\n    template <>\n    class client_characteristic_configurations< 0 >\n    {\n    public:\n        client_characteristic_configuration client_configurations()\n        {\n            return client_characteristic_configuration();\n        }\n    };\n\n}\n}\n\n#endif\n"
  },
  {
    "path": "bluetoe/utility/include/bluetoe/codes.hpp",
    "content": "#ifndef BLUETOE_CODES_HPP\n#define BLUETOE_CODES_HPP\n\n#include <cstdint>\n\nnamespace bluetoe {\nnamespace details {\n\n    static constexpr std::uint16_t default_att_mtu_size = 23;\n    static constexpr std::uint16_t default_lesc_mtu_size = 65;\n\n    enum class att_opcodes : std::uint8_t {\n        error_response              = 0x01,\n        exchange_mtu_request        = 0x02,\n        exchange_mtu_response       = 0x03,\n        find_information_request    = 0x04,\n        find_information_response   = 0x05,\n        find_by_type_value_request  = 0x06,\n        find_by_type_value_response = 0x07,\n        read_by_type_request        = 0x08,\n        read_by_type_response       = 0x09,\n        read_request                = 0x0A,\n        read_response               = 0x0B,\n        read_blob_request           = 0x0C,\n        read_blob_response          = 0x0D,\n        read_multiple_request       = 0x0E,\n        read_multiple_response      = 0x0F,\n        read_by_group_type_request  = 0x10,\n        read_by_group_type_response = 0x11,\n        write_request               = 0x12,\n        write_response              = 0x13,\n        prepare_write_request       = 0x16,\n        prepare_write_response      = 0x17,\n        execute_write_request       = 0x18,\n        execute_write_response      = 0x19,\n        write_command               = 0x52,\n        notification                = 0x1B,\n        indication                  = 0x1D,\n        confirmation                = 0x1E\n\n    };\n\n    constexpr std::uint8_t bits( att_opcodes c )\n    {\n        return static_cast< std::uint8_t >( c );\n    }\n\n    enum class att_error_codes : std::uint8_t {\n        invalid_handle                      = 0x01,\n        read_not_permitted,\n        write_not_permitted,\n        invalid_pdu,\n        insufficient_authentication,\n        request_not_supported,\n        invalid_offset,\n        insufficient_authorization,\n        prepare_queue_full,\n        attribute_not_found,\n        attribute_not_long,\n        insufficient_encryption_key_size,\n        invalid_attribute_value_length,\n        unlikely_error,\n        insufficient_encryption,\n        unsupported_group_type,\n        insufficient_resources\n    };\n\n    constexpr std::uint8_t bits( att_error_codes c )\n    {\n        return static_cast< std::uint8_t >( c );\n    }\n\n    enum class att_uuid_format : std::uint8_t {\n        short_16bit = 0x01,\n        long_128bit = 0x02\n    };\n\n    constexpr std::uint8_t bits( att_uuid_format c )\n    {\n        return static_cast< std::uint8_t >( c );\n    }\n\n    enum class gatt_uuids : std::uint16_t {\n        primary_service                     = 0x2800,\n        secondary_service                   = 0x2801,\n        include                             = 0x2802,\n        characteristic                      = 0x2803,\n        characteristic_user_description     = 0x2901,\n        client_characteristic_configuration = 0x2902,\n\n        internal_128bit_uuid    = 1\n    };\n\n    constexpr std::uint16_t bits( gatt_uuids c )\n    {\n        return static_cast< std::uint16_t >( c );\n    }\n\n    enum class gatt_characteristic_properties : std::uint8_t {\n        read                    = 0x02,\n        write_without_response  = 0x04,\n        write                   = 0x08,\n        notify                  = 0x10,\n        indicate                = 0x20\n    };\n\n    constexpr std::uint8_t bits( gatt_characteristic_properties c )\n    {\n        return static_cast< std::uint8_t >( c );\n    }\n\n    enum class gap_types : std::uint8_t {\n        flags                           = 0x01,\n        incomplete_service_uuids_16     = 0x02,\n        complete_service_uuids_16       = 0x03,\n        incomplete_service_uuids_128    = 0x06,\n        complete_service_uuids_128      = 0x07,\n        complete_local_name             = 0x09,\n        shortened_local_name            = 0x08,\n        tx_power_level                  = 0x0a,\n        appearance                      = 0x19,\n    };\n\n    constexpr std::uint8_t bits( gap_types c )\n    {\n        return static_cast< std::uint8_t >( c );\n    }\n\n    enum {\n        client_characteristic_configuration_notification_enabled = 1,\n        client_characteristic_configuration_indication_enabled   = 2\n    };\n\n    inline std::uint8_t* write_opcode( std::uint8_t* out, details::att_opcodes opcode )\n    {\n        *out = bits( opcode );\n        return out + 1;\n    }\n}\n\n\n/**\n * namespace for error codes, that should be convertable to int\n */\nnamespace error_codes {\n\n    /**\n     * @brief Error codes to be returned by read and write handlers for characteristic values\n     */\n    enum error_codes : std::uint8_t {\n        /**\n         * read or write request could be fulfilled without an error\n         */\n        success                             = 0x00,\n\n        /**\n         * The attribute handle given was not valid on this server.\n         */\n        invalid_handle                      = 0x01,\n\n        /**\n         * The attribute cannot be read.\n         */\n        read_not_permitted,\n\n        /**\n         * The attribute cannot be written.\n         */\n        write_not_permitted,\n\n        /**\n         * The attribute PDU was invalid.\n         */\n        invalid_pdu,\n\n        /**\n         * The attribute requires authentication before it can be read or written.\n         */\n        insufficient_authentication,\n\n        /**\n         * Attribute server does not support the request received from the client.\n         */\n        request_not_supported,\n\n        /**\n         * Offset specified was past the end of the attribute.\n         */\n        invalid_offset,\n\n        /**\n         * The attribute requires authorization before it can be read or written.\n         */\n        insufficient_authorization,\n\n        /**\n         * Too many prepare writes have been queued.\n         */\n        prepare_queue_full,\n\n        /**\n         * No attribute found within the given attri- bute handle range.\n         */\n        attribute_not_found,\n\n        /**\n         * The attribute cannot be read or written using the Read Blob Request.\n         */\n        attribute_not_long,\n\n        /**\n         * The Encryption Key Size used for encrypting this link is insufficient.\n         */\n        insufficient_encryption_key_size,\n\n        /**\n         * The attribute value length is invalid for the operation.\n         */\n        invalid_attribute_value_length,\n\n        /**\n         * The attribute request that was requested has encountered an error that was unlikely,\n         * and therefore could not be completed as requested.\n         */\n        unlikely_error,\n\n        /**\n         * The attribute requires encryption before it can be read or written.\n         */\n        insufficient_encryption,\n\n        /**\n         * The attribute type is not a supported grouping attribute as defined by a higher layer specification.\n         */\n        unsupported_group_type,\n\n        /**\n         * Insufficient Resources to complete the request.\n         */\n        insufficient_resources,\n\n        /**\n         * Start of range for application specific error codes\n         */\n        application_error_start             = 0x80,\n\n        /**\n         * Last code of the range for application specific error codes\n         */\n        application_error_end               = 0x9f,\n\n        /**\n         * The Out of Range error code is used when an attribute value is out of range as defined by\n         * a profile or service specification.\n         */\n        out_of_range                        = 0xff,\n\n        /**\n         * The Procedure Already in Progress error code is used when a profile or service request cannot\n         * be serviced because an operation that has been previously triggered is still in progress.\n         */\n        procedure_already_in_progress       = 0xfe,\n\n        /**\n         * The Client Characteristic Configuration Descriptor Improperly Configured error code is used\n         * when a Client Characteristic Configuration descriptor is not configured according to the\n         * requirements of the profile or service.\n         */\n        cccd_improperly_configured          = 0xfd\n    };\n}\n}\n#endif\n"
  },
  {
    "path": "bluetoe/utility/include/bluetoe/meta_tools.hpp",
    "content": "#ifndef BLUETOE_META_TOOLS_HPP\n#define BLUETOE_META_TOOLS_HPP\n\n#include <utility>\n#include <type_traits>\n#include <tuple>\n\n/**\n * @file bluetoe/meta_tools.hpp\n * This file contains all the generic meta template functions that are required by bluetoe\n */\nnamespace bluetoe {\nnamespace details {\n\n    template < typename T >\n    struct wrap {\n        using type = T;\n    };\n\n    /** @cond HIDDEN_SYMBOLS */\n    template < bool Select >\n    struct select_type_impl {\n        template < typename A, typename B >\n        using f = A;\n    };\n\n    template <>\n    struct select_type_impl< false > {\n        template < typename A, typename B >\n        using f = B;\n    };\n    /** @endcond */\n\n     /**\n      * @brief Select A or B by Select. If Select == true, the result is A; B otherwise\n      */\n    template < bool Select, typename A, typename B >\n    using select_type = wrap< typename select_type_impl< Select >::template f< A, B > >;\n\n    /**\n     * @brief Selects a template according to the given Select parameter. If select is true,\n     * the result will be A; B otherwise\n     *\n     * The result is named type, but it is a template.\n     */\n    template < bool Select, template < typename > class A, template < typename > class B >\n    struct select_template_t1 {\n        template < typename T1 >\n        using type = A< T1 >;\n    };\n\n    template < template < typename > class A, template < typename > class B >\n    struct select_template_t1< false, A, B > {\n        template < typename T1 >\n        using type = B< T1 >;\n    };\n\n    /** @cond HIDDEN_SYMBOLS */\n    template < typename Null, typename A >\n    struct or_type_impl {\n        template < typename >\n        using f = A;\n    };\n\n    template < typename Null >\n    struct or_type_impl< Null, Null > {\n        template < typename B >\n        using f = B;\n    };\n    /** @endcond */\n\n    /**\n     * @brief return A if A is not Null, otherwise return B if B is not Null, otherwise Null\n     */\n    template < typename Null, typename A, typename B >\n    using or_type = wrap< typename or_type_impl< Null, A >::template f< B > >;\n\n    /**\n     * @brief add A to B\n     */\n    template < class A, class B >\n    struct add_type\n    {\n        typedef std::tuple< A, B > type;\n    };\n\n    template < class T, class ... Ts >\n    struct add_type< T, std::tuple< Ts... > >\n    {\n        typedef std::tuple< T, Ts... > type;\n    };\n\n    template < class ...Ts, class T >\n    struct add_type< std::tuple< Ts... >, T >\n    {\n        typedef std::tuple< Ts..., T > type;\n    };\n\n    template < class ...As, class ...Bs >\n    struct add_type< std::tuple< As... >, std::tuple< Bs...> >\n    {\n        typedef std::tuple< As..., Bs... > type;\n    };\n\n    /*\n     * wildcard to be used when templates should be used within remove_if_equal\n     */\n    struct wildcard {};\n\n    /*\n     * Removes from a typelist (std::tuple) all elments that are equal to Zero\n     */\n    template < typename A, typename Zero >\n    struct remove_if_equal;\n\n    template < typename Zero >\n    struct remove_if_equal< std::tuple<>, Zero >\n    {\n        typedef std::tuple<> type;\n    };\n\n    template <\n        typename Type,\n        typename Zero\n     >\n    struct remove_if_equal< std::tuple< Type >, Zero >\n    {\n        typedef std::tuple< Type > type;\n    };\n\n    // two types are equal if they are the same types\n    template <\n        typename Zero\n     >\n    struct remove_if_equal< std::tuple< Zero >, Zero >\n    {\n        typedef std::tuple<> type;\n    };\n\n    // two types are equal if they are both templates and the Zero type has it's parameters replaces with wildcards\n    template <\n        template < typename ... > class Templ,\n        typename Type\n     >\n    struct remove_if_equal< std::tuple< Templ< Type > >, Templ< wildcard > >\n    {\n        typedef std::tuple<> type;\n    };\n\n    template <\n        typename Type,\n        typename ... Types,\n        typename Zero\n     >\n    struct remove_if_equal< std::tuple< Type, Types... >, Zero >\n    {\n        typedef typename add_type<\n            typename remove_if_equal< std::tuple< Type >, Zero >::type,\n            typename remove_if_equal< std::tuple< Types... >, Zero >::type\n        >::type type;\n    };\n\n    /*\n     * a tuple type with two elements\n     */\n    template < typename A, typename B >\n    struct pair {\n        typedef A first_type;\n        typedef B second_type;\n    };\n\n    template < typename T >\n    struct not_type\n    {\n        typedef std::integral_constant< bool, !T::value > type;\n    };\n\n    /*\n     * empty result\n     */\n    struct no_such_type {};\n\n    /*\n     * Last element from typelist or Default if list is empty\n     */\n    template < typename T, typename Default = no_such_type >\n    struct last_type;\n\n    template < typename Default >\n    struct last_type< std::tuple<>, Default >\n    {\n        using type = Default;\n    };\n\n    template < typename T, typename Default >\n    struct last_type< std::tuple< T >, Default >\n    {\n        using type = T;\n    };\n\n    template < typename ...Ts, typename T, typename Default >\n    struct last_type< std::tuple< T, Ts... >, Default >\n    {\n        using type = typename last_type< std::tuple< Ts... >, Default >::type;\n    };\n\n    template < typename T >\n    struct extract_meta_type\n    {\n        template < class U >\n        static typename U::meta_type check( U&& ) { return U::meta_type(); }\n        static no_such_type          check( ... ) { return no_such_type(); }\n\n        typedef decltype( check( std::declval< T >() ) ) meta_type;\n        typedef meta_type                                type;\n        typedef typename not_type<\n            typename std::is_same<\n                meta_type, no_such_type >::type >::type  has_meta_type;\n    };\n\n    /*\n     * finds the first type that has the embedded meta_type\n     */\n    template <\n        typename MetaType,\n        typename ... Types >\n    struct find_by_meta_type;\n\n    template <\n        typename MetaType >\n    struct find_by_meta_type< MetaType >\n    {\n        typedef no_such_type type;\n    };\n\n    template <\n        typename MetaType,\n        typename Type >\n    struct find_by_meta_type< MetaType, Type >\n    {\n        typedef extract_meta_type< Type > meta_type;\n        typedef typename select_type<\n            std::is_convertible< typename meta_type::type*, MetaType* >::value,\n            Type, no_such_type >::type type;\n    };\n\n    template <\n        typename MetaType,\n        typename Type,\n        typename ... Types >\n    struct find_by_meta_type< MetaType, Type, Types... >\n    {\n        typedef typename or_type<\n            no_such_type,\n            typename find_by_meta_type< MetaType, Type >::type,\n            typename find_by_meta_type< MetaType, Types... >::type >::type type;\n    };\n\n    /*\n     * finds the first type that has _not_ the embedded meta_type\n     */\n    template <\n        typename MetaType,\n        typename ... Types >\n    struct find_by_not_meta_type;\n\n    template <\n        typename MetaType >\n    struct find_by_not_meta_type< MetaType >\n    {\n        typedef no_such_type type;\n    };\n\n    template <\n        typename MetaType,\n        typename Type >\n    struct find_by_not_meta_type< MetaType, Type >\n    {\n        typedef extract_meta_type< Type > meta_type;\n        typedef typename select_type<\n            std::is_convertible< typename meta_type::type*, MetaType* >::value,\n            no_such_type, Type >::type type;\n    };\n\n    template <\n        typename MetaType,\n        typename Type,\n        typename ... Types >\n    struct find_by_not_meta_type< MetaType, Type, Types... >\n    {\n        typedef typename or_type<\n            no_such_type,\n            typename find_by_not_meta_type< MetaType, Type >::type,\n            typename find_by_not_meta_type< MetaType, Types... >::type >::type type;\n    };\n\n    /*\n     * finds all types that has the embedded meta_type\n     */\n    template <\n        typename MetaType,\n        typename ... Types >\n    struct find_all_by_meta_type;\n\n    template <\n        typename MetaType >\n    struct find_all_by_meta_type< MetaType >\n    {\n        typedef std::tuple<> type;\n    };\n\n    template <\n        typename MetaType,\n        typename Type,\n        typename ... Types >\n    struct find_all_by_meta_type< MetaType, Type, Types... >\n    {\n        typedef extract_meta_type< Type > meta_type;\n        typedef typename select_type<\n            std::is_convertible< typename meta_type::type*, MetaType* >::value,\n            typename add_type< Type, typename find_all_by_meta_type< MetaType, Types... >::type >::type,\n            typename find_all_by_meta_type< MetaType, Types... >::type >::type type;\n    };\n\n    template <\n        typename MetaType,\n        typename ... Types >\n    struct find_all_by_meta_type< MetaType, std::tuple< Types... > > : find_all_by_meta_type< MetaType, Types... > {};\n\n    /*\n     * finds all types that has not the embedded meta_type\n     */\n    template <\n        typename MetaType,\n        typename ... Types >\n    struct find_all_by_not_meta_type;\n\n    template <\n        typename MetaType >\n    struct find_all_by_not_meta_type< MetaType >\n    {\n        typedef std::tuple<> type;\n    };\n\n    template <\n        typename MetaType,\n        typename Type,\n        typename ... Types >\n    struct find_all_by_not_meta_type< MetaType, Type, Types... >\n    {\n        typedef extract_meta_type< Type > meta_type;\n        typedef typename select_type<\n            std::is_convertible< typename meta_type::type*, MetaType* >::value,\n            typename find_all_by_not_meta_type< MetaType, Types... >::type,\n            typename add_type< Type, typename find_all_by_not_meta_type< MetaType, Types... >::type >::type\n        >::type type;\n    };\n\n    template <\n        typename MetaType,\n        typename ... Types >\n    struct find_all_by_not_meta_type< MetaType, std::tuple< Types... > > : find_all_by_not_meta_type< MetaType, Types... > {};\n\n    /*\n     * groups a list of types by there meta types\n     *\n     * Returns a std::tuple with as much elements as MetaTypes where given. Every element in the result is a tuple containing\n     * the meta type followed by the result of a call to find_all_by_meta_type<>\n     */\n    template <\n        typename Types,\n        typename ... MetaTypes >\n    struct group_by_meta_types;\n\n    template <\n        typename ... Types >\n    struct group_by_meta_types< std::tuple< Types... > >\n    {\n        typedef std::tuple<> type;\n    };\n\n    template <\n        typename ... Types,\n        typename MetaType >\n    struct group_by_meta_types< std::tuple< Types... >, MetaType >\n    {\n        typedef std::tuple<\n            typename add_type<\n                MetaType,\n                typename find_all_by_meta_type< MetaType, Types... >::type\n            >::type\n        > type;\n    };\n\n    template <\n        typename ... Types,\n        typename MetaType,\n        typename ... MetaTypes >\n    struct group_by_meta_types< std::tuple< Types... >, MetaType, MetaTypes... >\n    {\n        typedef typename add_type<\n            typename group_by_meta_types< std::tuple< Types... >, MetaType >::type,\n            typename group_by_meta_types< std::tuple< Types... >, MetaTypes... >::type >::type type;\n    };\n\n    /**\n     * @brief just like group_by_meta_types, but the result has all std::tuple<> removed\n     */\n    template <\n        typename Types,\n        typename ... MetaTypes >\n    struct group_by_meta_types_without_empty_groups;\n\n    template <\n        typename ... Types,\n        typename ... MetaTypes >\n    struct group_by_meta_types_without_empty_groups< std::tuple< Types... >, MetaTypes...>\n    {\n        typedef typename remove_if_equal<\n            typename group_by_meta_types< std::tuple< Types... >, MetaTypes... >::type,\n            std::tuple< wildcard >\n        >::type type;\n    };\n\n\n    /*\n     * counts the number of Types with a given MetaType\n     */\n    template <\n        typename MetaType,\n        typename ... Types >\n    struct count_by_meta_type;\n\n    template <\n        typename MetaType >\n    struct count_by_meta_type< MetaType > {\n        enum { count = 0 };\n    };\n\n    template <\n        typename MetaType,\n        typename Type,\n        typename ... Types >\n    struct count_by_meta_type< MetaType, Type, Types... > {\n        typedef extract_meta_type< Type > meta_type;\n\n        enum { count = std::is_convertible< typename meta_type::type*, MetaType* >::value\n            ? 1 + count_by_meta_type< MetaType, Types... >::count\n            : 0 + count_by_meta_type< MetaType, Types... >::count\n        };\n    };\n\n    /*\n     * counts the number of types, the predicate returned true for an element applied to it\n     */\n    template <\n        typename List,\n        template < typename > class Predicate\n    >\n    struct count_if;\n\n    template <\n        template < typename > class Predicate\n    >\n    struct count_if< std::tuple<>, Predicate > : std::integral_constant< int, 0 > {};\n\n    template <\n        typename T,\n        template < typename > class Predicate\n    >\n    struct count_if< std::tuple< T >, Predicate > : std::integral_constant< int, Predicate< T >::value ? 1 : 0 > {};\n\n    template <\n        typename T,\n        typename ...Ts,\n        template < typename > class Predicate\n    >\n    struct count_if< std::tuple< T, Ts... >, Predicate > : std::integral_constant< int,\n        count_if< std::tuple< T >, Predicate >::value\n      + count_if< std::tuple< Ts... >, Predicate >::value > {};\n\n    /*\n     * sums up the result of a call to Predicate with every element from List\n     */\n    template <\n        typename List,\n        template < typename > class Predicate\n    >\n    struct sum_by;\n\n    template <\n        template < typename > class Predicate\n    >\n    struct sum_by< std::tuple<>, Predicate > : std::integral_constant< int, 0 > {};\n\n    template <\n        typename T,\n        template < typename > class Predicate\n    >\n    struct sum_by< std::tuple< T >, Predicate > : std::integral_constant< int, Predicate< T >::value > {};\n\n    template <\n        typename T,\n        typename ...Ts,\n        template < typename > class Predicate\n    >\n    struct sum_by< std::tuple< T, Ts... >, Predicate > : std::integral_constant< int,\n        sum_by< std::tuple< T >, Predicate >::value\n      + sum_by< std::tuple< Ts... >, Predicate >::value > {};\n\n    /**\n     * @brief returns true, if Option is given in Options\n     */\n    template <\n        typename Option,\n        typename ... Options >\n    struct has_option;\n\n    template <\n        typename Option >\n    struct has_option< Option > {\n        static bool constexpr value = false;\n    };\n\n    template <\n        typename Option,\n        typename FirstOption,\n        typename ... Options >\n    struct has_option< Option, FirstOption, Options... > {\n        static bool constexpr value =\n            std::is_same< Option, FirstOption >::value || has_option< Option, Options... >::value;\n    };\n\n    /**\n     * @brief executes f.each< O >() for every O in Options.\n     *\n     * For\n     * Example:\n     * @code\n    struct value_printer\n    {\n        template< typename O >\n        void each()\n        {\n            std::cout << x << 'n';\n        }\n    };\n\n    int main()\n    {\n        for_< Options... >::each( value_printer() );\n    }\n     * @endcode\n     */\n    template <\n        typename ... Options >\n    struct for_impl;\n\n    template <>\n    struct for_impl<>\n    {\n        template < typename Function >\n        static void each( Function )\n        {}\n    };\n\n    template <\n        typename Option,\n        typename ... Options >\n    struct for_impl< Option, Options... >\n    {\n        template < typename Function >\n        static void each( Function f )\n        {\n            f.template each< Option >();\n            for_impl< Options... >::template each< Function >( f );\n        }\n    };\n\n    template <\n        typename ... Options >\n    struct for_ : for_impl< Options... >\n    {\n    };\n\n    template <\n        typename ... Options >\n    struct for_< std::tuple< Options... > > : for_impl< Options... >\n    {\n    };\n\n    /**\n     * @brief finds the first element in the list, for which Func< O >::value is true. With O beeing one of List\n     */\n    template <\n        typename List,\n        template < typename > class Func\n    >\n    struct find_if;\n\n    template <\n        template < typename > class Func\n    >\n    struct find_if< std::tuple<>, Func > {\n        typedef no_such_type type;\n    };\n\n    template <\n        typename T,\n        typename ... Ts,\n        template < typename > class Func\n    >\n    struct find_if< std::tuple< T, Ts...>, Func > {\n        typedef typename select_type<\n            Func< T >::value,\n            T,\n            typename find_if< std::tuple< Ts... >, Func >::type >::type type;\n    };\n\n\n    template < typename ... Ts >\n    struct last_from_pack;\n\n    template < typename T >\n    struct last_from_pack< T > {\n        typedef T type;\n    };\n\n    template <\n        typename T,\n        typename ... Ts >\n    struct last_from_pack< T, Ts... > {\n        typedef typename last_from_pack< Ts... >::type type;\n    };\n\n    // defines an empty type with the given meta_type\n    template < typename MetaType >\n    struct empty_meta_type {\n        typedef MetaType meta_type;\n    };\n\n    template < typename ... Ts >\n    struct derive_from_impl;\n\n    template <>\n    struct derive_from_impl<> {};\n\n    template < typename T, typename ... Ts >\n    struct derive_from_impl< T, Ts... > : T, derive_from_impl< Ts... > {};\n\n    // derives from all types within the given typelist List\n    template < typename List >\n    struct derive_from;\n\n    template < typename ... Ts >\n    struct derive_from< std::tuple< Ts... > > : derive_from_impl< Ts... > {};\n\n    // fold a list with an operation\n    template <\n        typename List,\n        template < typename ListP, typename ElementP > class Operation,\n        typename Start = std::tuple<> >\n    struct fold;\n\n    template <\n        template < typename List, typename Element > class Operation,\n        typename Start >\n    struct fold< std::tuple<>, Operation, Start >\n    {\n        typedef Start type;\n    };\n\n    template <\n        typename T,\n        typename ... Ts,\n        template < typename List, typename Element > class Operation,\n        typename Start >\n    struct fold< std::tuple< T, Ts... >, Operation, Start >\n    {\n        typedef typename Operation< typename fold< std::tuple< Ts... >, Operation, Start >::type, T >::type type;\n    };\n\n    template <\n        typename List,\n        template < typename ListP, typename ElementP > class Operation,\n        typename Start = std::tuple<> >\n    struct fold_right : fold< List, Operation, Start > {};\n\n\n    template <\n        typename List,\n        template < typename ListP, typename ElementP > class Operation,\n        typename Start = std::tuple<> >\n    struct fold_left;\n\n    template < bool >\n    struct fold_left_impl;\n\n    template <>\n    struct fold_left_impl< false > {\n        template <\n            template < typename, typename > class,\n            typename Start,\n            typename ... >\n        using f = Start;\n    };\n\n    template <>\n    struct fold_left_impl< true > {\n        template <\n            template < typename, typename > class Operation,\n            typename Start,\n            typename T,\n            typename ... Ts >\n        using f = typename fold_left_impl< sizeof...(Ts) != 0 >::template f< Operation, typename Operation< Start, T >::type, Ts... >;\n    };\n\n    template <\n        typename ... Ts,\n        template < typename ListP, typename ElementP > class Operation,\n        typename Start >\n    struct fold_left< std::tuple< Ts... >, Operation, Start > :\n        wrap< typename fold_left_impl< sizeof...(Ts) != 0 >::template f< Operation, Start, Ts... > >\n    {};\n\n    template < template < typename > class Transform >\n    struct apply_transformation\n    {\n        template < typename List, typename Element >\n        struct apply\n        {\n            using type = typename add_type< List, typename Transform< Element >::type >::type;\n        };\n    };\n\n    /*\n     * transform a list into an other list of the same length\n     */\n    template <\n        typename List,\n        template < typename > class Transform\n    >\n    struct transform_list : fold_left< List, apply_transformation< Transform >::template apply > {};\n\n    // for a T in Ts, find the index of T in Ts\n    // If T is not in Ts, the resulting value is sizeof...(Ts)\n    template < typename T, typename ... Ts >\n    struct index_of;\n\n    // not in list:\n    template < typename T, typename O >\n    struct index_of< T, O > {\n        static constexpr unsigned value = 1;\n    };\n\n    // not in empty list\n    template < typename T >\n    struct index_of< T > {\n        static constexpr unsigned value = 0;\n    };\n\n    template < typename T >\n    struct index_of< T, T > {\n        static constexpr unsigned value = 0;\n    };\n\n    template < typename T, typename ... Ts >\n    struct index_of< T, T, Ts... > {\n        static constexpr unsigned value = 0;\n    };\n\n    template < typename T, typename O, typename ... Ts >\n    struct index_of< T, O, Ts... > {\n        static constexpr unsigned value = index_of< T, Ts... >::value + 1;\n    };\n\n    template < typename T, typename ... Ts >\n    struct index_of< T, std::tuple< Ts... > > : index_of< T, Ts... > {};\n\n    /*\n     * Insert T into Ts at the first position, that satisfies Order\n     */\n    template < template < typename, typename > class Order, typename T, typename ...Ts >\n    struct stable_insert;\n\n    template < template < typename, typename > class Order, typename T, typename ...Ts >\n    struct stable_insert< Order, T, std::tuple< Ts... > > : stable_insert< Order, T, Ts... > {};\n\n    template < template < typename, typename > class Order, typename T >\n    struct stable_insert< Order, T >\n    {\n        using type = std::tuple< T >;\n    };\n\n    template < template < typename, typename > class Order, typename T, typename First, typename ...Ts >\n    struct stable_insert< Order, T, First, Ts... >\n    {\n        using type = typename select_type<\n            Order< First, T  >::type::value,\n            typename add_type< First, typename stable_insert< Order, T, Ts... >::type >::type,\n            std::tuple< T, First, Ts... >\n        >::type;\n    };\n\n    /*\n     * stable sort a list of types based on a given order\n     *\n     * The order must take two types as argument and define type to be either std::true_type or std::false_type\n     */\n    template < template < typename, typename > class Order, typename ...Ts >\n    struct stable_sort;\n\n    template < template < typename, typename > class Order, typename ...Ts >\n    struct stable_sort< Order, std::tuple< Ts... > > : stable_sort< Order, Ts... > {};\n\n    template < template < typename, typename > class Order >\n    struct stable_sort< Order, std::tuple<> >\n    {\n        using type = std::tuple<>;\n    };\n\n    template < template < typename, typename > class Order >\n    struct stable_sort< Order >\n    {\n        using type = std::tuple<>;\n    };\n\n    template < template < typename, typename > class Order, typename T, typename ...Ts >\n    struct stable_sort< Order, T, Ts... >\n    {\n        using rest = typename stable_sort< Order, Ts... >::type;\n        using type = typename stable_insert< Order, T, rest >::type;\n    };\n\n    /*\n     * A map is a std::tuple< pair< Key, Value > >\n     */\n\n    // Returns the Value to the Key or no_such_type, if not found\n    template < typename Map, typename Key, typename Default = no_such_type >\n    struct map_find;\n\n    template < typename Key, typename Default >\n    struct map_find< std::tuple<>, Key, Default >\n    {\n        using type = Default;\n    };\n\n    template < typename Value, typename Key, typename ...Ts, typename Default >\n    struct map_find< std::tuple< pair< Key, Value >, Ts... >, Key, Default >\n    {\n        using type = Value;\n    };\n\n    template < typename Value, typename NotKey, typename Key, typename ...Ts, typename Default >\n    struct map_find< std::tuple< pair< NotKey, Value >, Ts... >, Key, Default >\n    {\n        using type = typename map_find< std::tuple< Ts... >, Key, Default >::type;\n    };\n\n    // Removes the key from the map\n    template < typename Map, typename Key >\n    struct map_erase;\n\n    template < typename Key >\n    struct map_erase< std::tuple<>, Key >\n    {\n        using type = std::tuple<>;\n    };\n\n    template < typename Key, typename Value, typename ...Ts >\n    struct map_erase< std::tuple< pair< Key, Value >, Ts... >, Key >\n    {\n        using type = std::tuple< Ts... >;\n    };\n\n    template < typename Key, typename NotKey, typename Value, typename ...Ts >\n    struct map_erase< std::tuple< pair< NotKey, Value >, Ts... >, Key >\n    {\n        using type = typename add_type<\n            pair< NotKey, Value >,\n            typename map_erase< std::tuple< Ts...>, Key >::type\n        >::type;\n    };\n\n    // inserts / replaces the Value under Key\n    template < typename Map, typename Key, typename Value >\n    struct map_insert\n    {\n        using type = typename add_type<\n            pair< Key, Value >,\n            typename map_erase< Map, Key >::type >::type;\n    };\n\n\n}\n}\n\n#endif\n\n"
  },
  {
    "path": "bluetoe/utility/include/bluetoe/ring.hpp",
    "content": "#ifndef BLUETOE_UTILITY_RING_HPP\n#define BLUETOE_UTILITY_RING_HPP\n\n#include <atomic>\n#include <cstdint>\n\nnamespace bluetoe {\nnamespace details {\n\n    /**\n     * @brief an atomic ring buffer\n     *\n     * Ring buffer that supports a single consumer, single producer which\n     * do not have to run in the same CPU context.\n     */\n    template < std::size_t S, typename T >\n    class ring\n    {\n    public:\n        /**\n         * @brief contructs an empty ring\n         */\n        ring();\n\n        bool try_push( const T& );\n\n        bool try_pop( T& );\n\n    private:\n        // queue is empty, if both point to the very same element\n        // if read_ptr_ != write_ptr_, the ring is not empty and data_[ read_ptr_ ]\n        // contains the next element to read from.\n        std::atomic_int read_ptr_;\n        std::atomic_int write_ptr_;\n\n        static constexpr std::size_t length = S + 1;\n\n        T data_[ length ];\n    };\n\n    // implementation\n    template < std::size_t S, typename T >\n    ring< S, T >::ring()\n        : read_ptr_( 0 )\n        , write_ptr_( 0 )\n    {\n        static_assert( ATOMIC_INT_LOCK_FREE, \"atomic_int is expected to be lock free\" );\n    }\n\n    template < std::size_t S, typename T >\n    bool ring< S, T >::try_push( const T& in )\n    {\n        const int read  = read_ptr_.load();\n        const int write = write_ptr_.load();\n        const int next  = ( write + 1 ) % length;\n\n        if ( next == read )\n            return false;\n\n        data_[ write ] = in;\n        write_ptr_.store( next );\n\n        return true;\n    }\n\n    template < std::size_t S, typename T >\n    bool ring< S, T >::try_pop( T& out )\n    {\n        const int read  = read_ptr_.load();\n        const int write = write_ptr_.load();\n\n        if ( read == write )\n            return false;\n\n        const int next  = ( read + 1 ) % length;\n\n        out = data_[ read ];\n        read_ptr_.store( next );\n\n        return true;\n    }\n\n}\n}\n\n#endif\n"
  },
  {
    "path": "bluetoe/uuid.hpp",
    "content": "#ifndef BLUETOE_UUID_HPP\n#define BLUETOE_UUID_HPP\n\nnamespace bluetoe {\nnamespace details {\n\n    template < std::uint64_t A, std::uint64_t B, std::uint64_t C, std::uint64_t D, std::uint64_t E >\n    struct check_uuid_parameters\n    {\n        static_assert( A < 0x100000000,      \"uuid: first group of bytes can not be longer than 4 bytes.\" );\n        static_assert( B < 0x10000,          \"uuid: second group of bytes can not be longer than 2 bytes.\" );\n        static_assert( C < 0x10000,          \"uuid: third group of bytes can not be longer than 2 bytes.\" );\n        static_assert( D < 0x10000,          \"uuid: 4th group of bytes can not be longer than 2 bytes.\" );\n        static_assert( E < 0x1000000000000l, \"uuid: last group of bytes can not be longer than 6 bytes.\" );\n        typedef void type;\n    };\n\n    template < std::uint64_t UUID >\n    struct check_uuid_parameter16\n    {\n        static_assert( UUID < 0x10000,       \"uuid16: a 16 bit UUID can not be longer than 4 bytes.\" );\n        typedef void type;\n    };\n\n    /**\n     * @brief a 128-Bit UUID\n     *\n     * The class takes 5 parameters to store the UUID in the usual form like this:\n     * @code{.cpp}\n     * bluetoe::uuid< 0xF0426E52, 0x4450, 0x4F3B, 0xB058, 0x5BAB1191D92A >\n     * @endcode\n     */\n    template <\n        std::uint64_t A,\n        std::uint64_t B,\n        std::uint64_t C,\n        std::uint64_t D,\n        std::uint64_t E,\n        typename = typename details::check_uuid_parameters< A, B, C, D, E >::type >\n    struct uuid\n    {\n        static constexpr std::uint8_t bytes[ 16 ] = {\n                ( E >> 0  ) & 0xff,\n                ( E >> 8  ) & 0xff,\n                ( E >> 16 ) & 0xff,\n                ( E >> 24 ) & 0xff,\n                ( E >> 32 ) & 0xff,\n                ( E >> 40 ) & 0xff,\n                ( D >> 0  ) & 0xff,\n                ( D >> 8  ) & 0xff,\n                ( C >> 0  ) & 0xff,\n                ( C >> 8  ) & 0xff,\n                ( B >> 0  ) & 0xff,\n                ( B >> 8  ) & 0xff,\n                ( A >> 0  ) & 0xff,\n                ( A >> 8  ) & 0xff,\n                ( A >> 16 ) & 0xff,\n                ( A >> 24 ) & 0xff\n            };\n        static constexpr bool is_128bit = true;\n\n        static std::uint16_t as_16bit() {\n            return A & 0xffff;\n        };\n    };\n\n    template <\n        std::uint64_t A,\n        std::uint64_t B,\n        std::uint64_t C,\n        std::uint64_t D,\n        std::uint64_t E,\n        typename F >\n    constexpr std::uint8_t uuid< A, B, C, D, E, F >::bytes[ 16 ];\n\n    /**\n     * @brief a 16-Bit UUID\n     */\n    template < std::uint64_t UUID, typename = typename check_uuid_parameter16< UUID >::type >\n    struct uuid16\n    {\n        static constexpr std::uint8_t bytes[ 2 ] = {\n                ( UUID >> 0 ) & 0xff,\n                ( UUID >> 8 ) & 0xff,\n            };\n        static constexpr bool is_128bit = false;\n\n        static constexpr std::uint16_t as_16bit() {\n            return UUID & 0xffff;\n        };\n    };\n\n    template < std::uint64_t UUID, typename A >\n    constexpr std::uint8_t uuid16< UUID, A >::bytes[ 2 ];\n\n    /**\n     * @brief the 128 bit Bluetooth Base UUID\n     */\n    struct bluetooth_base_uuid : uuid< 0x00000000 ,0x0000, 0x1000, 0x8000, 0x00805F9B34FB >\n    {\n        /**\n         * @brief constructs a 128 bit uuid from a 16 bit Bluetooth UUID\n         */\n        template < std::uint64_t A >\n        using from_16bit = uuid< A ,0x0000, 0x1000, 0x8000, 0x00805F9B34FB > ;\n    };\n\n\n\n}\n}\n\n#endif\n"
  },
  {
    "path": "bluetoe/write_queue.hpp",
    "content": "#ifndef BLUETOE_WRITE_QUEUE_HPP\n#define BLUETOE_WRITE_QUEUE_HPP\n\n#include <cstdint>\n#include <cstddef>\n#include <cassert>\n#include <utility>\n#include <bluetoe/meta_types.hpp>\n\nnamespace bluetoe {\n\n    namespace details {\n        struct write_queue_meta_type {};\n    }\n\n    /**\n     * @brief defines a write queue size that is shared among all connected clients\n     *\n     * Defines the size of a per server write queue in bytes. The queue is allocated within the server object.\n     * All connected clients share the same write queue. The write queue is needed to implement the\n     * \"Write Long Characteristic\" procedure defined by GATT.\n     *\n     * To write objects of the size N, the queue size must be ( ( N + 17 ) / 18 * 7 ) + N bytes (integer math). For example, if the\n     * size of the largest object to be writen is 100 bytes, than the queue size must be ( ( 100 + 17 ) / 18 * 7 ) + 100 = 142\n     *\n     * As all connections share one write queue, the whole queue is allocated to the first connection that starts writing a long characteristic\n     * value until that client is done with writing or gets disconnected. All othere connections will get an \"Prepare Queue Full\" error meanwhile.\n     *\n     * If no write queue size if given, the server will respond with \"Request Not Supported\" to a ATT \"Prepare Write Request\" or \"Execute Write Request\".\n     *\n     * @sa server\n     *\n     * example:\n     * @code\n    typedef bluetoe::server<\n        bluetoe::shared_write_queue< 128 >,\n    ...\n    > large_object_server;\n\n    typedef bluetoe::extend_server<\n        small_temperature_service,\n        bluetoe::server_name< name >\n    > small_named_temperature_service;\n\n     * @endcode\n     */\n    template < std::uint16_t S >\n    struct shared_write_queue {\n        /** @cond HIDDEN_SYMBOLS */\n        struct meta_type :\n            details::write_queue_meta_type,\n            details::valid_server_option_meta_type {};\n\n        static constexpr std::uint16_t queue_size = S;\n        /** @endcond */\n    };\n\nnamespace details {\n\n    /*\n     * Interface to access a write queue. All member named are some kind of prefixed with 'write_queue', because this type will be fixed into the server\n     */\n    template < typename QueueParameter >\n    class write_queue;\n\n    template < std::uint16_t S >\n    class write_queue< shared_write_queue< S > >\n    {\n    public:\n        write_queue();\n\n        /*\n         * Allocate n bytes for the given client. Returns 0 if it was not possible to allocate out of the queue.\n         * If successful, the function returns the start of an n byte size array.\n         */\n        template < typename ConData >\n        std::uint8_t* allocate_from_write_queue( std::size_t n, ConData& client );\n\n        /*\n         * Deallocates all elements allocated by the given client\n         */\n        template < typename ConData >\n        void free_write_queue( ConData& client );\n\n        /*\n         * return the first element of the queue for the given client. If no element was allocated, the function returns nullptr.\n         */\n        template < typename ConData >\n        std::pair< std::uint8_t*, std::size_t > first_write_queue_element( ConData& client );\n\n        /*\n         * Returns the next element in the queue to current. current must not be nullptr and must be obtained by a call to\n         * first_element() or next_element()\n         */\n        template < typename ConData >\n        std::pair< std::uint8_t*, std::size_t > next_write_queue_element( std::uint8_t* current, ConData& );\n    private:\n\n        std::size_t read_size( std::uint8_t* ) const;\n\n        void*           current_client_;\n        std::uint8_t    buffer_[ S ];\n        std::uint16_t   buffer_end_;\n    };\n\n    struct no_such_type;\n\n    template <>\n    class write_queue< no_such_type >\n    {\n    public:\n        template < typename ConData >\n        void free_write_queue( ConData& ) {}\n    };\n\n    /*\n     * guard to make sure, that free_write_queue is called when this guard goes out of scope\n     */\n    template < typename ConData, typename WriteQueue >\n    class write_queue_guard\n    {\n    public:\n        write_queue_guard( ConData& client, WriteQueue& queue );\n        ~write_queue_guard();\n\n    private:\n        write_queue_guard( const write_queue_guard& ) = delete;\n        write_queue_guard& operator=( const write_queue_guard& ) = delete;\n\n        ConData&    client_;\n        WriteQueue& queue_;\n    };\n\n    // implementation\n    template < std::uint16_t S >\n    write_queue< shared_write_queue< S > >::write_queue()\n        : current_client_( nullptr )\n        , buffer_end_( 0 )\n    {\n    }\n\n    template < std::uint16_t S >\n    template < typename ConData >\n    std::uint8_t* write_queue< shared_write_queue< S > >::allocate_from_write_queue( std::size_t size, ConData& client )\n    {\n        assert( size );\n\n        if ( size + 2 > static_cast< std::size_t >( S - buffer_end_ ) || ( current_client_ != nullptr && current_client_ != &client ) )\n            return nullptr;\n\n        buffer_[ buffer_end_ ]     = size & 0xff;\n        buffer_[ buffer_end_ + 1 ] = size >> 8;\n\n        current_client_ = &client;\n        buffer_end_    += size + 2;\n\n        return &buffer_[ buffer_end_ - size ];\n    }\n\n    template < std::uint16_t S >\n    template < typename ConData >\n    void write_queue< shared_write_queue< S > >::free_write_queue( ConData& client )\n    {\n        if( current_client_ == &client )\n        {\n            buffer_end_     = 0;\n            current_client_ = nullptr;\n        }\n    }\n\n    template < std::uint16_t S >\n    template < typename ConData >\n    std::pair< std::uint8_t*, std::size_t > write_queue< shared_write_queue< S > >::first_write_queue_element( ConData& client )\n    {\n        if( current_client_ != &client || buffer_end_ == 0 )\n        {\n            return std::make_pair( nullptr, 0 );\n        }\n\n        return std::make_pair( &buffer_[ 2 ], read_size( &buffer_[ 2 ] ) );\n    }\n\n    template < std::uint16_t S >\n    template < typename ConData >\n    std::pair< std::uint8_t*, std::size_t > write_queue< shared_write_queue< S > >::next_write_queue_element( std::uint8_t* last, ConData& client )\n    {\n        assert( last );\n        assert( last >= &buffer_[ 2 ] );\n        assert( last <= &buffer_[ S ] );\n        assert( &client == current_client_ );\n        static_cast< void >( client );\n\n        const std::size_t size = read_size( last );\n\n        // lets point last to the next size value\n        last += size;\n\n        return last == &buffer_[ buffer_end_ ]\n            ? std::make_pair( nullptr, 0 )\n            : std::make_pair( last + 2, read_size( last + 2 ) );\n    }\n\n    template < std::uint16_t S >\n    std::size_t write_queue< shared_write_queue< S > >::read_size( std::uint8_t* last ) const\n    {\n        return *( last - 2 ) + *( last - 1 ) * 256;\n    }\n\n    template < typename ConData, typename WriteQueue >\n    write_queue_guard< ConData, WriteQueue >::write_queue_guard( ConData& client, WriteQueue& queue )\n        : client_( client )\n        , queue_( queue )\n    {\n    }\n\n    template < typename ConData, typename WriteQueue >\n    write_queue_guard< ConData, WriteQueue >::~write_queue_guard()\n    {\n        queue_.free_write_queue( client_ );\n    }\n\n}\n}\n#endif\n"
  },
  {
    "path": "config/travisci_rsa.pub",
    "content": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDOIT9BGmfHAWtMT3qEEAdZBVl56x20zZ1lhOL+LVezhbxEdKVtsJleU/Eetxr9uZ/9Fwtaa1tmezT554jBLPMYpcyC1VmVIl+395lchqPZYQ08u1iiI5TKu5tN6tBEflKr6c+xHUH9m19ef6MLWoUqirYi0cMK4wIWjlMoKYCY23yHRPP4ObaW50puigAMl4Y8REmtBx7EHDWWUw9VWSVuhrg9zb4sC+fj9ffKdFk+EnhJni2Wf1su+T/I+JwGyL2ZVXOtR3/ZmR5QMbFEmwXylxsJIUFbpbGlz1ZkwRquB2+1E9VOJIxdYCANx73bI/JkIuxmaKxLunNXB4QycU87 travis@robitzki.de\n"
  },
  {
    "path": "documentation/customdoxygen.css",
    "content": "/* The standard CSS for doxygen 1.9.2 */\n\nbody, table, div, p, dl {\n\tfont: 400 14px/22px Roboto,sans-serif;\n}\n\np.reference, p.definition {\n\tfont: 400 14px/22px Roboto,sans-serif;\n}\n\n/* @group Heading Levels */\n\nh1.groupheader {\n\tfont-size: 150%;\n}\n\n.title {\n\tfont: 400 14px/28px Roboto,sans-serif;\n\tfont-size: 150%;\n\tfont-weight: bold;\n\tmargin: 10px 2px;\n}\n\nh2.groupheader {\n\tborder-bottom: 1px solid #879ECB;\n\tcolor: #354C7B;\n\tfont-size: 150%;\n\tfont-weight: normal;\n\tmargin-top: 1.75em;\n\tpadding-top: 8px;\n\tpadding-bottom: 4px;\n\twidth: 100%;\n}\n\nh3.groupheader {\n\tfont-size: 100%;\n}\n\nh1, h2, h3, h4, h5, h6 {\n\t-webkit-transition: text-shadow 0.5s linear;\n\t-moz-transition: text-shadow 0.5s linear;\n\t-ms-transition: text-shadow 0.5s linear;\n\t-o-transition: text-shadow 0.5s linear;\n\ttransition: text-shadow 0.5s linear;\n\tmargin-right: 15px;\n}\n\nh1.glow, h2.glow, h3.glow, h4.glow, h5.glow, h6.glow {\n\ttext-shadow: 0 0 15px cyan;\n}\n\ndt {\n\tfont-weight: bold;\n}\n\nul.multicol {\n\t-moz-column-gap: 1em;\n\t-webkit-column-gap: 1em;\n\tcolumn-gap: 1em;\n\t-moz-column-count: 3;\n\t-webkit-column-count: 3;\n\tcolumn-count: 3;\n}\n\np.startli, p.startdd {\n\tmargin-top: 2px;\n}\n\nth p.starttd, th p.intertd, th p.endtd {\n        font-size: 100%;\n        font-weight: 700;\n}\n\np.starttd {\n\tmargin-top: 0px;\n}\n\np.endli {\n\tmargin-bottom: 0px;\n}\n\np.enddd {\n\tmargin-bottom: 4px;\n}\n\np.endtd {\n\tmargin-bottom: 2px;\n}\n\np.interli {\n}\n\np.interdd {\n}\n\np.intertd {\n}\n\n/* @end */\n\ncaption {\n\tfont-weight: bold;\n}\n\nspan.legend {\n\tfont-size: 70%;\n\ttext-align: center;\n}\n\nh3.version {\n\tfont-size: 90%;\n\ttext-align: center;\n}\n\ndiv.navtab {\n\tborder-right: 1px solid #A3B4D7;\n\tpadding-right: 15px;\n\ttext-align: right;\n\tline-height: 110%;\n}\n\ndiv.navtab table {\n\tborder-spacing: 0;\n}\n\ntd.navtab {\n\tpadding-right: 6px;\n\tpadding-left: 6px;\n}\ntd.navtabHL {\n\tbackground-image: url('tab_a.png');\n\tbackground-repeat:repeat-x;\n\tpadding-right: 6px;\n\tpadding-left: 6px;\n}\n\ntd.navtabHL a, td.navtabHL a:visited {\n\tcolor: #fff;\n\ttext-shadow: 0px 1px 1px rgba(0, 0, 0, 1.0);\n}\n\na.navtab {\n\tfont-weight: bold;\n}\n\ndiv.qindex{\n\ttext-align: center;\n\twidth: 100%;\n\tline-height: 140%;\n\tfont-size: 130%;\n\tcolor: #A0A0A0;\n}\n\ndt.alphachar{\n\tfont-size: 180%;\n\tfont-weight: bold;\n}\n\n.alphachar a{\n\tcolor: black;\n}\n\n.alphachar a:hover, .alphachar a:visited{\n\ttext-decoration: none;\n}\n\n.classindex dl {\n\tpadding: 25px;\n\tcolumn-count:1\n}\n\n.classindex dd {\n\tdisplay:inline-block;\n\tmargin-left: 50px;\n\twidth: 90%;\n\tline-height: 1.15em;\n}\n\n.classindex dl.odd {\n\tbackground-color: #F8F9FC;\n}\n\n@media(min-width: 1120px) {\n\t.classindex dl {\n\t\tcolumn-count:2\n\t}\n}\n\n@media(min-width: 1320px) {\n\t.classindex dl {\n\t\tcolumn-count:3\n\t}\n}\n\n\n/* @group Link Styling */\n\na {\n\tcolor: #3D578C;\n\tfont-weight: normal;\n\ttext-decoration: none;\n}\n\n.contents a:visited {\n\tcolor: #4665A2;\n}\n\na:hover {\n\ttext-decoration: underline;\n}\n\n.contents a.qindexHL:visited {\n        color: #FFFFFF;\n}\n\na.el {\n\tfont-weight: bold;\n}\n\na.elRef {\n}\n\na.code, a.code:visited, a.line, a.line:visited {\n\tcolor: #4665A2; \n}\n\na.codeRef, a.codeRef:visited, a.lineRef, a.lineRef:visited {\n\tcolor: #4665A2; \n}\n\na.code.hl_class { /* style for links to class names in code snippets */ }\na.code.hl_struct { /* style for links to struct names in code snippets */ }\na.code.hl_union { /* style for links to union names in code snippets */ }\na.code.hl_interface { /* style for links to interface names in code snippets */ }\na.code.hl_protocol { /* style for links to protocol names in code snippets */ }\na.code.hl_category { /* style for links to category names in code snippets */ }\na.code.hl_exception { /* style for links to exception names in code snippets */ }\na.code.hl_service { /* style for links to service names in code snippets */ }\na.code.hl_singleton { /* style for links to singleton names in code snippets */ }\na.code.hl_concept { /* style for links to concept names in code snippets */ }\na.code.hl_namespace { /* style for links to namespace names in code snippets */ }\na.code.hl_package { /* style for links to package names in code snippets */ }\na.code.hl_define { /* style for links to macro names in code snippets */ }\na.code.hl_function { /* style for links to function names in code snippets */ }\na.code.hl_variable { /* style for links to variable names in code snippets */ }\na.code.hl_typedef { /* style for links to typedef names in code snippets */ }\na.code.hl_enumvalue { /* style for links to enum value names in code snippets */ }\na.code.hl_enumeration { /* style for links to enumeration names in code snippets */ }\na.code.hl_signal { /* style for links to Qt signal names in code snippets */ }\na.code.hl_slot { /* style for links to Qt slot names in code snippets */ }\na.code.hl_friend { /* style for links to friend names in code snippets */ }\na.code.hl_dcop { /* style for links to KDE3 DCOP names in code snippets */ }\na.code.hl_property { /* style for links to property names in code snippets */ }\na.code.hl_event { /* style for links to event names in code snippets */ }\na.code.hl_sequence { /* style for links to sequence names in code snippets */ }\na.code.hl_dictionary { /* style for links to dictionary names in code snippets */ }\n\n/* @end */\n\ndl.el {\n\tmargin-left: -1cm;\n}\n\nul {\n  overflow: hidden; /*Fixed: list item bullets overlap floating elements*/\n}\n\n#side-nav ul {\n  overflow: visible; /* reset ul rule for scroll bar in GENERATE_TREEVIEW window */\n}\n\n#main-nav ul {\n  overflow: visible; /* reset ul rule for the navigation bar drop down lists */\n}\n\n.fragment {\n  text-align: left;\n  direction: ltr;\n  overflow-x: auto; /*Fixed: fragment lines overlap floating elements*/\n  overflow-y: hidden;\n}\n\npre.fragment {\n        border: 1px solid #C4CFE5;\n        background-color: #FBFCFD;\n        padding: 4px 6px;\n        margin: 4px 8px 4px 2px;\n        overflow: auto;\n        word-wrap: break-word;\n        font-size:  9pt;\n        line-height: 125%;\n        font-family: monospace, fixed;\n        font-size: 105%;\n}\n\ndiv.fragment {\n  padding: 0 0 1px 0; /*Fixed: last line underline overlap border*/\n  margin: 4px 8px 4px 2px;\n\tbackground-color: #FBFCFD;\n\tborder: 1px solid #C4CFE5;\n}\n\ndiv.line {\n\tfont-family: monospace, fixed;\n        font-size: 13px;\n\tmin-height: 13px;\n\tline-height: 1.0;\n\ttext-wrap: unrestricted;\n\twhite-space: -moz-pre-wrap; /* Moz */\n\twhite-space: -pre-wrap;     /* Opera 4-6 */\n\twhite-space: -o-pre-wrap;   /* Opera 7 */\n\twhite-space: pre-wrap;      /* CSS3  */\n\tword-wrap: break-word;      /* IE 5.5+ */\n\ttext-indent: -53px;\n\tpadding-left: 53px;\n\tpadding-bottom: 0px;\n\tmargin: 0px;\n\t-webkit-transition-property: background-color, box-shadow;\n\t-webkit-transition-duration: 0.5s;\n\t-moz-transition-property: background-color, box-shadow;\n\t-moz-transition-duration: 0.5s;\n\t-ms-transition-property: background-color, box-shadow;\n\t-ms-transition-duration: 0.5s;\n\t-o-transition-property: background-color, box-shadow;\n\t-o-transition-duration: 0.5s;\n\ttransition-property: background-color, box-shadow;\n\ttransition-duration: 0.5s;\n}\n\ndiv.line:after {\n    content:\"\\000A\";\n    white-space: pre;\n}\n\ndiv.line.glow {\n\tbackground-color: cyan;\n\tbox-shadow: 0 0 10px cyan;\n}\n\n\nspan.lineno {\n\tpadding-right: 4px;\n        margin-right: 9px;\n\ttext-align: right;\n\tborder-right: 2px solid #0F0;\n\tbackground-color: #E8E8E8;\n        white-space: pre;\n}\nspan.lineno a {\n\tbackground-color: #D8D8D8;\n}\n\nspan.lineno a:hover {\n\tbackground-color: #C8C8C8;\n}\n\n.lineno {\n\t-webkit-touch-callout: none;\n\t-webkit-user-select: none;\n\t-khtml-user-select: none;\n\t-moz-user-select: none;\n\t-ms-user-select: none;\n\tuser-select: none;\n}\n\ndiv.ah, span.ah {\n\tbackground-color: black;\n\tfont-weight: bold;\n\tcolor: #FFFFFF;\n\tmargin-bottom: 3px;\n\tmargin-top: 3px;\n\tpadding: 0.2em;\n\tborder: solid thin #333;\n\tborder-radius: 0.5em;\n\t-webkit-border-radius: .5em;\n\t-moz-border-radius: .5em;\n\tbox-shadow: 2px 2px 3px #999;\n\t-webkit-box-shadow: 2px 2px 3px #999;\n\t-moz-box-shadow: rgba(0, 0, 0, 0.15) 2px 2px 2px;\n\tbackground-image: -webkit-gradient(linear, left top, left bottom, from(#eee), to(#000),color-stop(0.3, #444));\n\tbackground-image: -moz-linear-gradient(center top, #eee 0%, #444 40%, #000 110%);\n}\n\ndiv.classindex ul {\n        list-style: none;\n        padding-left: 0;\n}\n\ndiv.classindex span.ai {\n        display: inline-block;\n}\n\ndiv.groupHeader {\n\tmargin-left: 16px;\n\tmargin-top: 12px;\n\tfont-weight: bold;\n}\n\ndiv.groupText {\n\tmargin-left: 16px;\n\tfont-style: italic;\n}\n\nbody {\n\tbackground-color: white;\n\tcolor: black;\n        margin: 0;\n}\n\ndiv.contents {\n\tmargin-top: 10px;\n\tmargin-left: 12px;\n\tmargin-right: 8px;\n}\n\ntd.indexkey {\n\tbackground-color: #EBEFF6;\n\tfont-weight: bold;\n\tborder: 1px solid #C4CFE5;\n\tmargin: 2px 0px 2px 0;\n\tpadding: 2px 10px;\n        white-space: nowrap;\n        vertical-align: top;\n}\n\ntd.indexvalue {\n\tbackground-color: #EBEFF6;\n\tborder: 1px solid #C4CFE5;\n\tpadding: 2px 10px;\n\tmargin: 2px 0px;\n}\n\ntr.memlist {\n\tbackground-color: #EEF1F7;\n}\n\np.formulaDsp {\n\ttext-align: center;\n}\n\nimg.formulaDsp {\n\t\n}\n\nimg.formulaInl, img.inline {\n\tvertical-align: middle;\n}\n\ndiv.center {\n\ttext-align: center;\n        margin-top: 0px;\n        margin-bottom: 0px;\n        padding: 0px;\n}\n\ndiv.center img {\n\tborder: 0px;\n}\n\naddress.footer {\n\ttext-align: right;\n\tpadding-right: 12px;\n}\n\nimg.footer {\n\tborder: 0px;\n\tvertical-align: middle;\n}\n\n.compoundTemplParams {\n\tcolor: #4665A2;\n\tfont-size: 80%;\n\tline-height: 120%;\n}\n\n/* @group Code Colorization */\n\nspan.keyword {\n\tcolor: #008000\n}\n\nspan.keywordtype {\n\tcolor: #604020\n}\n\nspan.keywordflow {\n\tcolor: #e08000\n}\n\nspan.comment {\n\tcolor: #800000\n}\n\nspan.preprocessor {\n\tcolor: #806020\n}\n\nspan.stringliteral {\n\tcolor: #002080\n}\n\nspan.charliteral {\n\tcolor: #008080\n}\n\nspan.vhdldigit { \n\tcolor: #ff00ff \n}\n\nspan.vhdlchar { \n\tcolor: #000000 \n}\n\nspan.vhdlkeyword { \n\tcolor: #700070 \n}\n\nspan.vhdllogic { \n\tcolor: #ff0000 \n}\n\nblockquote {\n        background-color: #F7F8FB;\n        border-left: 2px solid #9CAFD4;\n        margin: 0 24px 0 4px;\n        padding: 0 12px 0 16px;\n}\n\nblockquote.DocNodeRTL {\n   border-left: 0;\n   border-right: 2px solid #9CAFD4;\n   margin: 0 4px 0 24px;\n   padding: 0 16px 0 12px;\n}\n\n/* @end */\n\n/*\n.search {\n\tcolor: #003399;\n\tfont-weight: bold;\n}\n\nform.search {\n\tmargin-bottom: 0px;\n\tmargin-top: 0px;\n}\n\ninput.search {\n\tfont-size: 75%;\n\tcolor: #000080;\n\tfont-weight: normal;\n\tbackground-color: #e8eef2;\n}\n*/\n\ntd.tiny {\n\tfont-size: 75%;\n}\n\n.dirtab {\n\tpadding: 4px;\n\tborder-collapse: collapse;\n\tborder: 1px solid #A3B4D7;\n}\n\nth.dirtab {\n\tbackground: #EBEFF6;\n\tfont-weight: bold;\n}\n\nhr {\n\theight: 0px;\n\tborder: none;\n\tborder-top: 1px solid #4A6AAA;\n}\n\nhr.footer {\n\theight: 1px;\n}\n\n/* @group Member Descriptions */\n\ntable.memberdecls {\n\tborder-spacing: 0px;\n\tpadding: 0px;\n}\n\n.memberdecls td, .fieldtable tr {\n\t-webkit-transition-property: background-color, box-shadow;\n\t-webkit-transition-duration: 0.5s;\n\t-moz-transition-property: background-color, box-shadow;\n\t-moz-transition-duration: 0.5s;\n\t-ms-transition-property: background-color, box-shadow;\n\t-ms-transition-duration: 0.5s;\n\t-o-transition-property: background-color, box-shadow;\n\t-o-transition-duration: 0.5s;\n\ttransition-property: background-color, box-shadow;\n\ttransition-duration: 0.5s;\n}\n\n.memberdecls td.glow, .fieldtable tr.glow {\n\tbackground-color: cyan;\n\tbox-shadow: 0 0 15px cyan;\n}\n\n.mdescLeft, .mdescRight,\n.memItemLeft, .memItemRight,\n.memTemplItemLeft, .memTemplItemRight, .memTemplParams {\n\tbackground-color: #F9FAFC;\n\tborder: none;\n\tmargin: 4px;\n\tpadding: 1px 0 0 8px;\n}\n\n.mdescLeft, .mdescRight {\n\tpadding: 0px 8px 4px 8px;\n\tcolor: #555;\n}\n\n.memSeparator {\n        border-bottom: 1px solid #DEE4F0;\n        line-height: 1px;\n        margin: 0px;\n        padding: 0px;\n}\n\n.memItemLeft, .memTemplItemLeft {\n        white-space: nowrap;\n}\n\n.memItemRight, .memTemplItemRight {\n\twidth: 100%;\n}\n\n.memTemplParams {\n\tcolor: #4665A2;\n        white-space: nowrap;\n\tfont-size: 80%;\n}\n\n/* @end */\n\n/* @group Member Details */\n\n/* Styles for detailed member documentation */\n\n.memtitle {\n\tpadding: 8px;\n\tborder-top: 1px solid #A8B8D9;\n\tborder-left: 1px solid #A8B8D9;\n\tborder-right: 1px solid #A8B8D9;\n\tborder-top-right-radius: 4px;\n\tborder-top-left-radius: 4px;\n\tmargin-bottom: -1px;\n\tbackground-image: url('nav_f.png');\n\tbackground-repeat: repeat-x;\n\tbackground-color: #E2E8F2;\n\tline-height: 1.25;\n\tfont-weight: 300;\n\tfloat:left;\n}\n\n.permalink\n{\n        font-size: 65%;\n        display: inline-block;\n        vertical-align: middle;\n}\n\n.memtemplate {\n\tfont-size: 80%;\n\tcolor: #4665A2;\n\tfont-weight: normal;\n\tmargin-left: 9px;\n}\n\n.memnav {\n\tbackground-color: #EBEFF6;\n\tborder: 1px solid #A3B4D7;\n\ttext-align: center;\n\tmargin: 2px;\n\tmargin-right: 15px;\n\tpadding: 2px;\n}\n\n.mempage {\n\twidth: 100%;\n}\n\n.memitem {\n\tpadding: 0;\n\tmargin-bottom: 10px;\n\tmargin-right: 5px;\n        -webkit-transition: box-shadow 0.5s linear;\n        -moz-transition: box-shadow 0.5s linear;\n        -ms-transition: box-shadow 0.5s linear;\n        -o-transition: box-shadow 0.5s linear;\n        transition: box-shadow 0.5s linear;\n        display: table !important;\n        width: 100%;\n}\n\n.memitem.glow {\n         box-shadow: 0 0 15px cyan;\n}\n\n.memname {\n        font-weight: 400;\n        margin-left: 6px;\n}\n\n.memname td {\n\tvertical-align: bottom;\n}\n\n.memproto, dl.reflist dt {\n        border-top: 1px solid #A8B8D9;\n        border-left: 1px solid #A8B8D9;\n        border-right: 1px solid #A8B8D9;\n        padding: 6px 0px 6px 0px;\n        color: #253555;\n        font-weight: bold;\n        text-shadow: 0px 1px 1px rgba(255, 255, 255, 0.9);\n        background-color: #DFE5F1;\n        /* opera specific markup */\n        box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15);\n        border-top-right-radius: 4px;\n        /* firefox specific markup */\n        -moz-box-shadow: rgba(0, 0, 0, 0.15) 5px 5px 5px;\n        -moz-border-radius-topright: 4px;\n        /* webkit specific markup */\n        -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15);\n        -webkit-border-top-right-radius: 4px;\n\n}\n\n.overload {\n        font-family: \"courier new\",courier,monospace;\n\tfont-size: 65%;\n}\n\n.memdoc, dl.reflist dd {\n        border-bottom: 1px solid #A8B8D9;      \n        border-left: 1px solid #A8B8D9;      \n        border-right: 1px solid #A8B8D9; \n        padding: 6px 10px 2px 10px;\n        background-color: #FBFCFD;\n        border-top-width: 0;\n        background-image:url('nav_g.png');\n        background-repeat:repeat-x;\n        background-color: #FFFFFF;\n        /* opera specific markup */\n        border-bottom-left-radius: 4px;\n        border-bottom-right-radius: 4px;\n        box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15);\n        /* firefox specific markup */\n        -moz-border-radius-bottomleft: 4px;\n        -moz-border-radius-bottomright: 4px;\n        -moz-box-shadow: rgba(0, 0, 0, 0.15) 5px 5px 5px;\n        /* webkit specific markup */\n        -webkit-border-bottom-left-radius: 4px;\n        -webkit-border-bottom-right-radius: 4px;\n        -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15);\n}\n\ndl.reflist dt {\n        padding: 5px;\n}\n\ndl.reflist dd {\n        margin: 0px 0px 10px 0px;\n        padding: 5px;\n}\n\n.paramkey {\n\ttext-align: right;\n}\n\n.paramtype {\n\twhite-space: nowrap;\n}\n\n.paramname {\n\tcolor: #602020;\n\twhite-space: nowrap;\n}\n.paramname em {\n\tfont-style: normal;\n}\n.paramname code {\n        line-height: 14px;\n}\n\n.params, .retval, .exception, .tparams {\n        margin-left: 0px;\n        padding-left: 0px;\n}       \n\n.params .paramname, .retval .paramname, .tparams .paramname, .exception .paramname {\n        font-weight: bold;\n        vertical-align: top;\n}\n        \n.params .paramtype, .tparams .paramtype {\n        font-style: italic;\n        vertical-align: top;\n}       \n        \n.params .paramdir, .tparams .paramdir {\n        font-family: \"courier new\",courier,monospace;\n        vertical-align: top;\n}\n\ntable.mlabels {\n\tborder-spacing: 0px;\n}\n\ntd.mlabels-left {\n\twidth: 100%;\n\tpadding: 0px;\n}\n\ntd.mlabels-right {\n\tvertical-align: bottom;\n\tpadding: 0px;\n\twhite-space: nowrap;\n}\n\nspan.mlabels {\n        margin-left: 8px;\n}\n\nspan.mlabel {\n        background-color: #728DC1;\n        border-top:1px solid #5373B4;\n        border-left:1px solid #5373B4;\n        border-right:1px solid #C4CFE5;\n        border-bottom:1px solid #C4CFE5;\n\ttext-shadow: none;\n\tcolor: white;\n\tmargin-right: 4px;\n\tpadding: 2px 3px;\n\tborder-radius: 3px;\n\tfont-size: 7pt;\n\twhite-space: nowrap;\n\tvertical-align: middle;\n}\n\n\n\n/* @end */\n\n/* these are for tree view inside a (index) page */\n\ndiv.directory {\n        margin: 10px 0px;\n        border-top: 1px solid #9CAFD4;\n        border-bottom: 1px solid #9CAFD4;\n        width: 100%;\n}\n\n.directory table {\n        border-collapse:collapse;\n}\n\n.directory td {\n        margin: 0px;\n        padding: 0px;\n\tvertical-align: top;\n}\n\n.directory td.entry {\n        white-space: nowrap;\n        padding-right: 6px;\n\tpadding-top: 3px;\n}\n\n.directory td.entry a {\n        outline:none;\n}\n\n.directory td.entry a img {\n        border: none;\n}\n\n.directory td.desc {\n        width: 100%;\n        padding-left: 6px;\n\tpadding-right: 6px;\n\tpadding-top: 3px;\n\tborder-left: 1px solid rgba(0,0,0,0.05);\n}\n\n.directory tr.even {\n\tpadding-left: 6px;\n\tbackground-color: #F7F8FB;\n}\n\n.directory img {\n\tvertical-align: -30%;\n}\n\n.directory .levels {\n        white-space: nowrap;\n        width: 100%;\n        text-align: right;\n        font-size: 9pt;\n}\n\n.directory .levels span {\n        cursor: pointer;\n        padding-left: 2px;\n        padding-right: 2px;\n\tcolor: #3D578C;\n}\n\n.arrow {\n    color: #9CAFD4;\n    -webkit-user-select: none;\n    -khtml-user-select: none;\n    -moz-user-select: none;\n    -ms-user-select: none;\n    user-select: none;\n    cursor: pointer;\n    font-size: 80%;\n    display: inline-block;\n    width: 16px;\n    height: 22px;\n}\n\n.icon {\n    font-family: Arial, Helvetica;\n    font-weight: bold;\n    font-size: 12px;\n    height: 14px;\n    width: 16px;\n    display: inline-block;\n    background-color: #728DC1;\n    color: white;\n    text-align: center;\n    border-radius: 4px;\n    margin-left: 2px;\n    margin-right: 2px;\n}\n\n.icona {\n    width: 24px;\n    height: 22px;\n    display: inline-block;\n}\n\n.iconfopen {\n    width: 24px;\n    height: 18px;\n    margin-bottom: 4px;\n    background-image:url('folderopen.png');\n    background-position: 0px -4px;\n    background-repeat: repeat-y;\n    vertical-align:top;\n    display: inline-block;\n}\n\n.iconfclosed {\n    width: 24px;\n    height: 18px;\n    margin-bottom: 4px;\n    background-image:url('folderclosed.png');\n    background-position: 0px -4px;\n    background-repeat: repeat-y;\n    vertical-align:top;\n    display: inline-block;\n}\n\n.icondoc {\n    width: 24px;\n    height: 18px;\n    margin-bottom: 4px;\n    background-image:url('doc.png');\n    background-position: 0px -4px;\n    background-repeat: repeat-y;\n    vertical-align:top;\n    display: inline-block;\n}\n\ntable.directory {\n    font: 400 14px Roboto,sans-serif;\n}\n\n/* @end */\n\ndiv.dynheader {\n        margin-top: 8px;\n\t-webkit-touch-callout: none;\n\t-webkit-user-select: none;\n\t-khtml-user-select: none;\n\t-moz-user-select: none;\n\t-ms-user-select: none;\n\tuser-select: none;\n}\n\naddress {\n\tfont-style: normal;\n\tcolor: #2A3D61;\n}\n\ntable.doxtable caption {\n\tcaption-side: top;\n}\n\ntable.doxtable {\n\tborder-collapse:collapse;\n        margin-top: 4px;\n        margin-bottom: 4px;\n}\n\ntable.doxtable td, table.doxtable th {\n\tborder: 1px solid #2D4068;\n\tpadding: 3px 7px 2px;\n}\n\ntable.doxtable th {\n\tbackground-color: #374F7F;\n\tcolor: #FFFFFF;\n\tfont-size: 110%;\n\tpadding-bottom: 4px;\n\tpadding-top: 5px;\n}\n\ntable.fieldtable {\n        /*width: 100%;*/\n        margin-bottom: 10px;\n        border: 1px solid #A8B8D9;\n        border-spacing: 0px;\n        -moz-border-radius: 4px;\n        -webkit-border-radius: 4px;\n        border-radius: 4px;\n        -moz-box-shadow: rgba(0, 0, 0, 0.15) 2px 2px 2px;\n        -webkit-box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.15);\n        box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.15);\n}\n\n.fieldtable td, .fieldtable th {\n        padding: 3px 7px 2px;\n}\n\n.fieldtable td.fieldtype, .fieldtable td.fieldname {\n        white-space: nowrap;\n        border-right: 1px solid #A8B8D9;\n        border-bottom: 1px solid #A8B8D9;\n        vertical-align: top;\n}\n\n.fieldtable td.fieldname {\n        padding-top: 3px;\n}\n\n.fieldtable td.fielddoc {\n        border-bottom: 1px solid #A8B8D9;\n        /*width: 100%;*/\n}\n\n.fieldtable td.fielddoc p:first-child {\n        margin-top: 0px;\n}       \n        \n.fieldtable td.fielddoc p:last-child {\n        margin-bottom: 2px;\n}\n\n.fieldtable tr:last-child td {\n        border-bottom: none;\n}\n\n.fieldtable th {\n        background-image:url('nav_f.png');\n        background-repeat:repeat-x;\n        background-color: #E2E8F2;\n        font-size: 90%;\n        color: #253555;\n        padding-bottom: 4px;\n        padding-top: 5px;\n        text-align:left;\n        font-weight: 400;\n        -moz-border-radius-topleft: 4px;\n        -moz-border-radius-topright: 4px;\n        -webkit-border-top-left-radius: 4px;\n        -webkit-border-top-right-radius: 4px;\n        border-top-left-radius: 4px;\n        border-top-right-radius: 4px;\n        border-bottom: 1px solid #A8B8D9;\n}\n\n\n.tabsearch {\n\ttop: 0px;\n\tleft: 10px;\n\theight: 36px;\n\tbackground-image: url('tab_b.png');\n\tz-index: 101;\n\toverflow: hidden;\n\tfont-size: 13px;\n}\n\n.navpath ul\n{\n\tfont-size: 11px;\n\tbackground-image:url('tab_b.png');\n\tbackground-repeat:repeat-x;\n\tbackground-position: 0 -5px;\n\theight:30px;\n\tline-height:30px;\n\tcolor:#8AA0CC;\n\tborder:solid 1px #C2CDE4;\n\toverflow:hidden;\n\tmargin:0px;\n\tpadding:0px;\n}\n\n.navpath li\n{\n\tlist-style-type:none;\n\tfloat:left;\n\tpadding-left:10px;\n\tpadding-right:15px;\n\tbackground-image:url('bc_s.png');\n\tbackground-repeat:no-repeat;\n\tbackground-position:right;\n\tcolor:#364D7C;\n}\n\n.navpath li.navelem a\n{\n\theight:32px;\n\tdisplay:block;\n\ttext-decoration: none;\n\toutline: none;\n\tcolor: #283A5D;\n\tfont-family: 'Lucida Grande',Geneva,Helvetica,Arial,sans-serif;\n\ttext-shadow: 0px 1px 1px rgba(255, 255, 255, 0.9);\n\ttext-decoration: none;        \n}\n\n.navpath li.navelem a:hover\n{\n\tcolor:#6884BD;\n}\n\n.navpath li.footer\n{\n        list-style-type:none;\n        float:right;\n        padding-left:10px;\n        padding-right:15px;\n        background-image:none;\n        background-repeat:no-repeat;\n        background-position:right;\n        color:#364D7C;\n        font-size: 8pt;\n}\n\n\ndiv.summary\n{\n\tfloat: right;\n\tfont-size: 8pt;\n\tpadding-right: 5px;\n\twidth: 50%;\n\ttext-align: right;\n}       \n\ndiv.summary a\n{\n\twhite-space: nowrap;\n}\n\ntable.classindex\n{\n        margin: 10px;\n        white-space: nowrap;\n        margin-left: 3%;\n        margin-right: 3%;\n        width: 94%;\n        border: 0;\n        border-spacing: 0; \n        padding: 0;\n}\n\ndiv.ingroups\n{\n\tfont-size: 8pt;\n\twidth: 50%;\n\ttext-align: left;\n}\n\ndiv.ingroups a\n{\n\twhite-space: nowrap;\n}\n\ndiv.header\n{\n        background-image:url('nav_h.png');\n        background-repeat:repeat-x;\n\tbackground-color: #F9FAFC;\n\tmargin:  0px;\n\tborder-bottom: 1px solid #C4CFE5;\n}\n\ndiv.headertitle\n{\n\tpadding: 5px 5px 5px 10px;\n}\n\n.PageDocRTL-title div.headertitle {\n  text-align: right;\n  direction: rtl;\n}\n\ndl {\n        padding: 0 0 0 0;\n}\n\n/* dl.note, dl.warning, dl.attention, dl.pre, dl.post, dl.invariant, dl.deprecated, dl.todo, dl.test, dl.bug, dl.examples */\ndl.section {\n\tmargin-left: 0px;\n\tpadding-left: 0px;\n}\n\ndl.section.DocNodeRTL {\n  margin-right: 0px;\n  padding-right: 0px;\n}\n\ndl.note {\n  margin-left: -7px;\n  padding-left: 3px;\n  border-left: 4px solid;\n  border-color: #D0C000;\n}\n\ndl.note.DocNodeRTL {\n  margin-left: 0;\n  padding-left: 0;\n  border-left: 0;\n  margin-right: -7px;\n  padding-right: 3px;\n  border-right: 4px solid;\n  border-color: #D0C000;\n}\n\ndl.warning, dl.attention {\n  margin-left: -7px;\n  padding-left: 3px;\n  border-left: 4px solid;\n  border-color: #FF0000;\n}\n\ndl.warning.DocNodeRTL, dl.attention.DocNodeRTL {\n  margin-left: 0;\n  padding-left: 0;\n  border-left: 0;\n  margin-right: -7px;\n  padding-right: 3px;\n  border-right: 4px solid;\n  border-color: #FF0000;\n}\n\ndl.pre, dl.post, dl.invariant {\n  margin-left: -7px;\n  padding-left: 3px;\n  border-left: 4px solid;\n  border-color: #00D000;\n}\n\ndl.pre.DocNodeRTL, dl.post.DocNodeRTL, dl.invariant.DocNodeRTL {\n  margin-left: 0;\n  padding-left: 0;\n  border-left: 0;\n  margin-right: -7px;\n  padding-right: 3px;\n  border-right: 4px solid;\n  border-color: #00D000;\n}\n\ndl.deprecated {\n  margin-left: -7px;\n  padding-left: 3px;\n  border-left: 4px solid;\n  border-color: #505050;\n}\n\ndl.deprecated.DocNodeRTL {\n  margin-left: 0;\n  padding-left: 0;\n  border-left: 0;\n  margin-right: -7px;\n  padding-right: 3px;\n  border-right: 4px solid;\n  border-color: #505050;\n}\n\ndl.todo {\n  margin-left: -7px;\n  padding-left: 3px;\n  border-left: 4px solid;\n  border-color: #00C0E0;\n}\n\ndl.todo.DocNodeRTL {\n  margin-left: 0;\n  padding-left: 0;\n  border-left: 0;\n  margin-right: -7px;\n  padding-right: 3px;\n  border-right: 4px solid;\n  border-color: #00C0E0;\n}\n\ndl.test {\n  margin-left: -7px;\n  padding-left: 3px;\n  border-left: 4px solid;\n  border-color: #3030E0;\n}\n\ndl.test.DocNodeRTL {\n  margin-left: 0;\n  padding-left: 0;\n  border-left: 0;\n  margin-right: -7px;\n  padding-right: 3px;\n  border-right: 4px solid;\n  border-color: #3030E0;\n}\n\ndl.bug {\n  margin-left: -7px;\n  padding-left: 3px;\n  border-left: 4px solid;\n  border-color: #C08050;\n}\n\ndl.bug.DocNodeRTL {\n  margin-left: 0;\n  padding-left: 0;\n  border-left: 0;\n  margin-right: -7px;\n  padding-right: 3px;\n  border-right: 4px solid;\n  border-color: #C08050;\n}\n\ndl.section dd {\n\tmargin-bottom: 6px;\n}\n\n\n#projectlogo\n{\n\ttext-align: center;\n\tvertical-align: bottom;\n\tborder-collapse: separate;\n}\n \n#projectlogo img\n{ \n\tborder: 0px none;\n    height: 130px;\n}\n \n#projectalign\n{\n        vertical-align: middle;\n}\n\n#projectname\n{\n\tfont: 200% Tahoma, Arial,sans-serif;\n\tmargin: 0px;\n\tpadding: 2px 0px;\n}\n    \n#projectbrief\n{\n\tfont: 90% Tahoma, Arial,sans-serif;\n\tmargin: 0px;\n\tpadding: 0px;\n}\n\n#projectnumber\n{\n\tfont: 50% Tahoma, Arial,sans-serif;\n\tmargin: 0px;\n\tpadding: 0px;\n}\n\n#titlearea\n{\n\tpadding: 0px;\n\tmargin: 0px;\n\twidth: 100%;\n\tborder-bottom: 1px solid #5373B4;\n}\n\n.image\n{\n        text-align: center;\n}\n\n.dotgraph\n{\n        text-align: center;\n}\n\n.mscgraph\n{\n        text-align: center;\n}\n\n.plantumlgraph\n{\n        text-align: center;\n}\n\n.diagraph\n{\n        text-align: center;\n}\n\n.caption\n{\n\tfont-weight: bold;\n}\n\ndiv.zoom\n{\n\tborder: 1px solid #90A5CE;\n}\n\ndl.citelist {\n        margin-bottom:50px;\n}\n\ndl.citelist dt {\n        color:#334975;\n        float:left;\n        font-weight:bold;\n        margin-right:10px;\n        padding:5px;\n        text-align:right;\n        width:52px;\n}\n\ndl.citelist dd {\n        margin:2px 0 2px 72px;\n        padding:5px 0;\n}\n\ndiv.toc {\n        padding: 14px 25px;\n        background-color: #F4F6FA;\n        border: 1px solid #D8DFEE;\n        border-radius: 7px 7px 7px 7px;\n        float: right;\n        height: auto;\n        margin: 0 8px 10px 10px;\n        width: 200px;\n}\n\n.PageDocRTL-title div.toc {\n  float: left !important;\n  text-align: right;\n}\n\ndiv.toc li {\n        background: url(\"bdwn.png\") no-repeat scroll 0 5px transparent;\n        font: 10px/1.2 Verdana,DejaVu Sans,Geneva,sans-serif;\n        margin-top: 5px;\n        padding-left: 10px;\n        padding-top: 2px;\n}\n\n.PageDocRTL-title div.toc li {\n  background-position-x: right !important;\n  padding-left: 0 !important;\n  padding-right: 10px;\n}\n\ndiv.toc h3 {\n        font: bold 12px/1.2 Arial,FreeSans,sans-serif;\n\tcolor: #4665A2;\n        border-bottom: 0 none;\n        margin: 0;\n}\n\ndiv.toc ul {\n        list-style: none outside none;\n        border: medium none;\n        padding: 0px;\n}       \n\ndiv.toc li.level1 {\n        margin-left: 0px;\n}\n\ndiv.toc li.level2 {\n        margin-left: 15px;\n}\n\ndiv.toc li.level3 {\n        margin-left: 30px;\n}\n\ndiv.toc li.level4 {\n        margin-left: 45px;\n}\n\nspan.emoji {\n        /* font family used at the site: https://unicode.org/emoji/charts/full-emoji-list.html\n         * font-family: \"Noto Color Emoji\", \"Apple Color Emoji\", \"Segoe UI Emoji\", Times, Symbola, Aegyptus, Code2000, Code2001, Code2002, Musica, serif, LastResort;\n         */\n}\n\n.PageDocRTL-title div.toc li.level1 {\n  margin-left: 0 !important;\n  margin-right: 0;\n}\n\n.PageDocRTL-title div.toc li.level2 {\n  margin-left: 0 !important;\n  margin-right: 15px;\n}\n\n.PageDocRTL-title div.toc li.level3 {\n  margin-left: 0 !important;\n  margin-right: 30px;\n}\n\n.PageDocRTL-title div.toc li.level4 {\n  margin-left: 0 !important;\n  margin-right: 45px;\n}\n\n.inherit_header {\n        font-weight: bold;\n        color: gray;\n        cursor: pointer;\n\t-webkit-touch-callout: none;\n\t-webkit-user-select: none;\n\t-khtml-user-select: none;\n\t-moz-user-select: none;\n\t-ms-user-select: none;\n\tuser-select: none;\n}\n\n.inherit_header td {\n        padding: 6px 0px 2px 5px;\n}\n\n.inherit {\n        display: none;\n}\n\ntr.heading h2 {\n        margin-top: 12px;\n        margin-bottom: 4px;\n}\n\n/* tooltip related style info */\n\n.ttc {\n        position: absolute;\n        display: none;\n}\n\n#powerTip {\n\tcursor: default;\n\twhite-space: nowrap;\n\tbackground-color: white;\n\tborder: 1px solid gray;\n\tborder-radius: 4px 4px 4px 4px;\n\tbox-shadow: 1px 1px 7px gray;\n\tdisplay: none;\n\tfont-size: smaller;\n\tmax-width: 80%;\n\topacity: 0.9;\n\tpadding: 1ex 1em 1em;\n\tposition: absolute;\n\tz-index: 2147483647;\n}\n\n#powerTip div.ttdoc {\n        color: grey;\n\tfont-style: italic;\n}\n\n#powerTip div.ttname a {\n        font-weight: bold;\n}\n\n#powerTip div.ttname {\n        font-weight: bold;\n}\n\n#powerTip div.ttdeci {\n        color: #006318;\n}\n\n#powerTip div {\n        margin: 0px;\n        padding: 0px;\n        font: 12px/16px Roboto,sans-serif;\n}\n\n#powerTip:before, #powerTip:after {\n\tcontent: \"\";\n\tposition: absolute;\n\tmargin: 0px;\n}\n\n#powerTip.n:after,  #powerTip.n:before,\n#powerTip.s:after,  #powerTip.s:before,\n#powerTip.w:after,  #powerTip.w:before,\n#powerTip.e:after,  #powerTip.e:before,\n#powerTip.ne:after, #powerTip.ne:before,\n#powerTip.se:after, #powerTip.se:before,\n#powerTip.nw:after, #powerTip.nw:before,\n#powerTip.sw:after, #powerTip.sw:before {\n\tborder: solid transparent;\n\tcontent: \" \";\n\theight: 0;\n\twidth: 0;\n\tposition: absolute;\n}\n\n#powerTip.n:after,  #powerTip.s:after,\n#powerTip.w:after,  #powerTip.e:after,\n#powerTip.nw:after, #powerTip.ne:after,\n#powerTip.sw:after, #powerTip.se:after {\n\tborder-color: rgba(255, 255, 255, 0);\n}\n\n#powerTip.n:before,  #powerTip.s:before,\n#powerTip.w:before,  #powerTip.e:before,\n#powerTip.nw:before, #powerTip.ne:before,\n#powerTip.sw:before, #powerTip.se:before {\n\tborder-color: rgba(128, 128, 128, 0);\n}\n\n#powerTip.n:after,  #powerTip.n:before,\n#powerTip.ne:after, #powerTip.ne:before,\n#powerTip.nw:after, #powerTip.nw:before {\n\ttop: 100%;\n}\n\n#powerTip.n:after, #powerTip.ne:after, #powerTip.nw:after {\n\tborder-top-color: #FFFFFF;\n\tborder-width: 10px;\n\tmargin: 0px -10px;\n}\n#powerTip.n:before {\n\tborder-top-color: #808080;\n\tborder-width: 11px;\n\tmargin: 0px -11px;\n}\n#powerTip.n:after, #powerTip.n:before {\n\tleft: 50%;\n}\n\n#powerTip.nw:after, #powerTip.nw:before {\n\tright: 14px;\n}\n\n#powerTip.ne:after, #powerTip.ne:before {\n\tleft: 14px;\n}\n\n#powerTip.s:after,  #powerTip.s:before,\n#powerTip.se:after, #powerTip.se:before,\n#powerTip.sw:after, #powerTip.sw:before {\n\tbottom: 100%;\n}\n\n#powerTip.s:after, #powerTip.se:after, #powerTip.sw:after {\n\tborder-bottom-color: #FFFFFF;\n\tborder-width: 10px;\n\tmargin: 0px -10px;\n}\n\n#powerTip.s:before, #powerTip.se:before, #powerTip.sw:before {\n\tborder-bottom-color: #808080;\n\tborder-width: 11px;\n\tmargin: 0px -11px;\n}\n\n#powerTip.s:after, #powerTip.s:before {\n\tleft: 50%;\n}\n\n#powerTip.sw:after, #powerTip.sw:before {\n\tright: 14px;\n}\n\n#powerTip.se:after, #powerTip.se:before {\n\tleft: 14px;\n}\n\n#powerTip.e:after, #powerTip.e:before {\n\tleft: 100%;\n}\n#powerTip.e:after {\n\tborder-left-color: #FFFFFF;\n\tborder-width: 10px;\n\ttop: 50%;\n\tmargin-top: -10px;\n}\n#powerTip.e:before {\n\tborder-left-color: #808080;\n\tborder-width: 11px;\n\ttop: 50%;\n\tmargin-top: -11px;\n}\n\n#powerTip.w:after, #powerTip.w:before {\n\tright: 100%;\n}\n#powerTip.w:after {\n\tborder-right-color: #FFFFFF;\n\tborder-width: 10px;\n\ttop: 50%;\n\tmargin-top: -10px;\n}\n#powerTip.w:before {\n\tborder-right-color: #808080;\n\tborder-width: 11px;\n\ttop: 50%;\n\tmargin-top: -11px;\n}\n\n@media print\n{\n  #top { display: none; }\n  #side-nav { display: none; }\n  #nav-path { display: none; }\n  body { overflow:visible; }\n  h1, h2, h3, h4, h5, h6 { page-break-after: avoid; }\n  .summary { display: none; }\n  .memitem { page-break-inside: avoid; }\n  #doc-content\n  {\n    margin-left:0 !important;\n    height:auto !important;\n    width:auto !important;\n    overflow:inherit;\n    display:inline;\n  }\n}\n\n/* @group Markdown */\n\ntable.markdownTable {\n\tborder-collapse:collapse;\n        margin-top: 4px;\n        margin-bottom: 4px;\n}\n\ntable.markdownTable td, table.markdownTable th {\n\tborder: 1px solid #2D4068;\n\tpadding: 3px 7px 2px;\n}\n\ntable.markdownTable tr {\n}\n\nth.markdownTableHeadLeft, th.markdownTableHeadRight, th.markdownTableHeadCenter, th.markdownTableHeadNone {\n\tbackground-color: #374F7F;\n\tcolor: #FFFFFF;\n\tfont-size: 110%;\n\tpadding-bottom: 4px;\n\tpadding-top: 5px;\n}\n\nth.markdownTableHeadLeft, td.markdownTableBodyLeft {\n\ttext-align: left\n}\n\nth.markdownTableHeadRight, td.markdownTableBodyRight {\n\ttext-align: right\n}\n\nth.markdownTableHeadCenter, td.markdownTableBodyCenter {\n\ttext-align: center\n}\n\n.DocNodeRTL {\n  text-align: right;\n  direction: rtl;\n}\n\n.DocNodeLTR {\n  text-align: left;\n  direction: ltr;\n}\n\ntable.DocNodeRTL {\n   width: auto;\n   margin-right: 0;\n   margin-left: auto;\n}\n\ntable.DocNodeLTR {\n   width: auto;\n   margin-right: auto;\n   margin-left: 0;\n}\n\ntt, code, kbd, samp\n{\n  display: inline-block;\n  direction:ltr; \n}\n/* @end */\n\nu {\n\ttext-decoration: underline;\n}\n\n"
  },
  {
    "path": "examples/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.13)\n\n# Prevent in source build, add this options before project keyword\nset(CMAKE_DISABLE_SOURCE_CHANGES ON)\nset(CMAKE_DISABLE_IN_SOURCE_BUILD ON)\n\nset(AVAILABLE_BOARDS PCA10056 PCA10040)\nset(AVAILABLE_BINDINGS NRF52840 NRF52833 NRF52832 NRF52820 NRF52811 NRF52810 NRF52805)\n\ninclude(./cmake/deduce.cmake)\n\n# Check BLUETOE_BOARD and BLUETOE_BINDING for correct values / combinations\nif (DEFINED BLUETOE_BOARD)\n    set_property(CACHE BLUETOE_BOARD PROPERTY STRINGS ${AVAILABLE_BOARDS})\n\n    if (DEFINED BLUETOE_BINDING)\n        message(FATAL_ERROR \"'BLUETOE_BOARD' is set to '${BLUETOE_BOARD}' while 'BLUETOE_BINDING' is set to '${BLUETOE_BINDING}'. It is not expected to have both variables beeing set!\")\n    endif()\n\n    if (NOT ${BLUETOE_BOARD} IN_LIST AVAILABLE_BOARDS)\n        message(FATAL_ERROR \"'BLUETOE_BOARD' is set to '${BLUETOE_BOARD}', which is an invalid value. Supported values are: ${AVAILABLE_BOARDS}\")\n    endif()\n\n    deduce_binding(BLUETOE_BINDING ${BLUETOE_BOARD})\nelse()\n    if (NOT DEFINED BLUETOE_BINDING)\n        message(FATAL_ERROR \"For a custom hardware, the 'BLUETOE_BINDING' cache variable is expected to be set.\")\n    endif()\n\n    if (NOT ${BLUETOE_BINDING} IN_LIST AVAILABLE_BINDINGS)\n        message(FATAL_ERROR \"'BLUETOE_BINDING' is set to '${BLUETOE_BINDING}', which is an invalid value. Supported values are: ${AVAILABLE_BINDINGS}\")\n    endif()\n\n    set_property(CACHE BLUETOE_BINDING PROPERTY STRINGS ${AVAILABLE_BINDINGS})\nendif()\n\n\n# Currently all examples are compiled with arm-none-eabi-gcc\nset(CMAKE_TOOLCHAIN_FILE ./cmake/gcc-arm-none-eabi.cmake)\n\nproject(bluetoe_examples CXX C)\n\n# set_preprocessore_macros(${BLUETOE_BOARD} ${BLUETOE_BINDING})\ndeduce_bluetoe_binding(BINDING ${BLUETOE_BINDING})\n\nmessage(\"BLUETOE_BOARD: ${BLUETOE_BOARD}\")\nmessage(\"BLUETOE_BINDING: ${BLUETOE_BINDING}\")\nmessage(\"BINDING: ${BINDING}\")\n\n# include hardware specific compile options and definitions that must be apllied to the whole project\ninclude(${BINDING}_toolchain_support/platform.cmake)\n\n# set global compile options that are hardware independent, these will be used to build the applications (examples)\n# and will also be used to build bluetoe library\n# Put every function and object into it's own section and ask the linker to remove unreferenced sections\nadd_compile_options(-ffunction-sections -fdata-sections)\nadd_link_options(LINKER:--gc-sections LINKER:--warn-common)\n\n# add global options to cpp targets\nadd_compile_options($<$<COMPILE_LANGUAGE:CXX>:-ftemplate-backtrace-limit=0>)\nadd_compile_options($<$<COMPILE_LANGUAGE:CXX>:-fvisibility-inlines-hidden>)\nadd_compile_options($<$<COMPILE_LANGUAGE:CXX>:-fno-rtti>)\nadd_compile_options($<$<COMPILE_LANGUAGE:CXX>:-fno-exceptions>)\n\n# Optimizations / Debug\nadd_compile_options($<IF:$<CONFIG:Debug>,-O0,-Os>)\nadd_compile_definitions($<$<NOT:$<CONFIG:Debug>>:NDEBUG>)\n\n# Regardles of build type: Debug informations just make it into the elf file, never into the final binary\nadd_compile_options(-g)\nadd_link_options(-g)\n\n# Standard libraries\nadd_compile_options(-nostdlib)\nadd_link_options(--sysroot=/usr/local/arm/arm-none-eabi -lm -lstdc++ -lsupc++ -nostdlib --specs=nano.specs -static)\n\n# toolchain support targets\nadd_subdirectory(${BINDING}_toolchain_support)\n\n# Resonale implementation of assert (no __PRETTY_FUNCTION__)\nadd_subdirectory(assert)\n\n# bluetoe library\nadd_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/.. ${CMAKE_CURRENT_BINARY_DIR}/bluetoe)\n\n# Support for basic peripherals used in the examples\nadd_subdirectory(spl)\n\n# Additional settings for the Bluetoe library itself:\ntarget_link_libraries(bluetoe_iface INTERFACE assert::arm)\n\nfunction(add_bluetoe_example target_name)\n    add_executable(${target_name} ${target_name}.cpp runtime_gcc.cpp)\n    set_target_properties(${target_name}\n        PROPERTIES\n            OUTPUT_NAME ${target_name}.elf)\n\n    add_linker_script(${target_name})\n\n    target_link_libraries(${target_name}\n        PUBLIC\n            assert::arm\n        PRIVATE\n            spl\n            toolchain::${BINDING}\n            startup::${BINDING}\n            bluetoe::bindings::${BINDING}\n    )\n\n    add_custom_target(${target_name}.artifacts ALL\n            COMMAND ${CMAKE_OBJCOPY} -S -O ihex ${target_name}.elf ${target_name}.hex\n            COMMAND ${CMAKE_OBJCOPY} -S -O binary --only-section=.text ${target_name}.elf ${target_name}.bin\n            COMMAND ${CMAKE_OBJDUMP} -hS ${target_name}.elf > ${target_name}.lss\n            COMMAND ${CMAKE_SIZE} ${target_name}.elf\n            )\n    add_dependencies(${target_name}.artifacts ${target_name})\n\n\n    define_flash_command(${target_name})\nendfunction()\n\nadd_bluetoe_example(blinky)\nadd_bluetoe_example(blinky_with_oob)\nadd_bluetoe_example(blinky_without_encryption)\nadd_bluetoe_example(blinky_with_lesc_and_legacy_pairing)\nadd_bluetoe_example(thermometer)\nadd_bluetoe_example(cycling_speed_and_cadence)\nadd_bluetoe_example(bootloader)\n# TODO: scheduled radio tests is not an actual example, and needs to be\n# TODO: generalized to work with all scheduled radio implementations (nrf51, nrf52, ... )\n# TODO: add_bluetoe_example(scheduled_radio_tests)\nadd_bluetoe_example(keyboard)\nadd_bluetoe_example(nrf52_high_cpu_load)\nadd_bluetoe_example(custom_advertising)\nadd_bluetoe_example(gpio)\nadd_bluetoe_example(synchronized_callbacks)\n"
  },
  {
    "path": "examples/README.md",
    "content": "# Bluetoe Examples\n\n## Predicates / Required Tools and Libraries\n\nBluetoe used CMake for building and GCC as compiler. Different plattform bindings require different, additional libraries. Building for Nordic Microcontrollers requires a Nordic SDK to be installed on the build computer.\n\nTo use the build process of the Bluetoe examples to directly flash examples, using a JLink debug probe, the nRF Command Line Tools must be installed (nrfjprog).\n\nTo configure the build, some CMake cache variables are required to be set.\n\nThe build tries to find the required `arm-none-eabi-gcc` on its own. If you want to use a specific version of `arm-none-eabi-gcc`, you can set the CMake cache variable `ARM_GCC_TOOL_PATH` to point to the local installation of `arm-none-eabi-gcc` (the path, wich contains the `bin` directory).\n\n### Nordic SDK\n\nTo build for Nordic hardware, the Nordic SDK must be installed on the build machine. `NRF5_SDK_ROOT` must then point to the installation.\n\n## Configure Examples to run on your Hardware\n\nCurrently, there is support for following eval boards:\n- PCA10056 (nRF52840 based eval board from Nordic)\n- PCA10040 (nRF52832 based eval board from Nordic)\n\nTo configure the build of the examples, set the cmake cache variable `BLUETOE_BOARD` to one of the values above.\n\n### Configure Exampels to run on custom Hardware\n\nTo run the examples on hardware that is not compatible with one of the eval boards, you have to tell Bluetoe, which microcontroller / system you want the examples build for. Currently, there is support for the following microcontrollers:\n- NRF52840\n- NRF52833\n- NRF52832\n- NRF52820\n- NRF52811\n- NRF52810\n- NRF52805\n\nTo configure the build for one of the microcontrollers, set the cmake cache variable `BLUETOE_BINDING` to one of the values above.\n\nNote: it is not required to set `BLUETOE_BINDING` if you want to build the examples for one of the supported eval boards, in which case, you would set `BLUETOE_BOARD` to the board identification.\n\n### Change Pin Allocations for your Hardware\n\nThe examples are using some GPIO pins to utilizes some LEDs and / or buttons. To map the used Buttons and LEDs to your hardware, please change the layout in the file resources.hpp to fit your hardware. You will find a self-explanatory section at the end of that file.\n\n## Support for JLink\n\nAll Nordic eval boards come with an embedded Jlink SWD debug probe, that can be used to flash the examples. To configure the build to enable directly flashing of an example, set the CMake cache variable `BLUETOE_JLINK` to the serial number of the JLink that should be used.\n\nIf `BLUETOE_JLINK` is given to the build, for every example, there will be a target that is the name of the example with a `.flash` appended. For example, to build and flash the bootloader example, the target name will be: `bootloader.flash`\n\nOn a Nordic eval board, you can read the required serial number of the JLink from the white sticker on the board (the longer number on the bottom of the sticker).\n\n## Example Configuration of CMake\n\nIn all cases, the build starts by creating a build folder in the examples directory of Bluetoe and changing into it:\n\n    mkdir build\n    cd build\n\nAssumed, you want to build the examples for the PCA10040 eval board, you would set the `BLUETOE_BOARD` cache variable accordingly and build the examples:\n\n    cmake -DBLUETOE_BOARD=PCA10040 ..\n\nIf you also want to configure the embedded debug probe of the eval board:\n\n    cmake -DBLUETOE_BOARD=PCA10040 -DBLUETOE_JLINK=683004602 ..\n\nTo build all exmples:\n\n    make all\n\nTo build and flash just the blinky example:\n\n    make blinky.flash\n\nIf you want to build a specific examples, you can use the example name and append a `.artifacts` to the name to build all binaries (elf file, hex file and bin file) and to get the information of the size of the resulting binary. So, if you want to build, for example, just the blinky example, build the `blinky.artifacts` target:\n\n    make blinky.artifacts\n\n"
  },
  {
    "path": "examples/assert/CMakeLists.txt",
    "content": "add_library(arm_assert INTERFACE)\nadd_library(assert::arm ALIAS arm_assert)\n\ntarget_sources(arm_assert\n    INTERFACE\n        assert.cpp)\n\ntarget_include_directories(arm_assert\n    SYSTEM INTERFACE\n        .)\n"
  },
  {
    "path": "examples/assert/assert.cpp",
    "content": "#include <assert.h>\n\nextern \"C\" void HardFault_Handler() __attribute__ ((noreturn));\n\nextern \"C\" void __assert_hash_func( assert_hash_type )\n{\n    HardFault_Handler();\n}\n"
  },
  {
    "path": "examples/assert/assert.h",
    "content": "#ifndef SOURCE_ASSERT_ASSERT_H\n#define SOURCE_ASSERT_ASSERT_H\n\n#include <cstdint>\n\n#ifdef USING_ASSERT_HASH\nextern \"C++\" {\n#   include \"assert_hash/assert_hash.hpp\"\n}\n#endif\n\n#undef assert\n\nusing assert_hash_type = std::uint32_t;\n\n#ifdef NDEBUG           /* required by ANSI standard */\n#   define assert(__e) ((void)0)\n#else\n#   ifdef USING_ASSERT_HASH\n#       define assert(__e) ((__e) ? (void)0 : __assert_hash_func ( assert_hash::file_and_line_hash< assert_hash_type >( __FILE__, __LINE__ )) )\n#   else\n#       define assert(__e) ((__e) ? (void)0 : __assert_hash_func ( 0 ) )\n#   endif /* USING_ASSERT_HASH */\n#endif /* !NDEBUG */\n\nextern \"C\" void __assert_hash_func(assert_hash_type) __attribute__((__noreturn__));\n\n#endif\n"
  },
  {
    "path": "examples/assert/cassert",
    "content": "#include <assert.h>"
  },
  {
    "path": "examples/ble_flash/CMakeLists.txt",
    "content": "add_custom_target(flash_tests.run\n   COMMAND mocha --compilers coffee:coffee-script/register ${CMAKE_CURRENT_LIST_DIR}/flash_tests.coffee)\n\nadd_custom_target(crc_tests.run\n   COMMAND mocha --compilers coffee:coffee-script/register ${CMAKE_CURRENT_LIST_DIR}/crc_tests.coffee)\n"
  },
  {
    "path": "examples/ble_flash/ble_flash.coffee",
    "content": "raise = (text)->\n    console.log text\n    process.exit 1\n\nFlashMemory = require( './flash.coffee' ).FlashMemory\nnoble       = require 'noble'\nutil        = require 'util'\nfs          = require 'fs'\noptions     = require('minimist')(\n    process.argv.slice(2), {\n        boolean: ['help', 'version', 'list', 'verbose'],\n        string: ['address', 'device', 'flash'],\n        alias: {\n            'help': ['h'],\n            'address': ['a'],\n            'device' : ['d'],\n            'version': ['v'],\n            'list'   : ['l'],\n            'flash'  : ['f'],\n            'verbose': ['V']\n        }\n        unknown: ( field )->\n            raise \"Unrecognizes argument \\\"#{field}\\\"\"\n    })\n\nVERBOSE                     = options[ 'verbose' ]\n\nBOOTLOADER_SERVICE_UUID     = '7d295f4d28504f57b595837f5753f8a9'\nCONTROL_POINT_UUID          = '7d295f4d28504f57b595837f5753f8a9'\nDATA_UUID                   = '7d295f4d28504f57b595837f5753f8aa'\nPROGRESS_UUID               = '7d295f4d28504f57b595837f5753f8ab'\nALL_CHARACTERISTIC_UUIDS    = [ CONTROL_POINT_UUID, DATA_UUID, PROGRESS_UUID ]\n\ncontrol_point_char          = null\ndata_char                   = null\nprogress_char               = null\n\nOPC_GET_VERSION = 0\nOPC_GET_CRC     = 1\nOPC_GET_SIZES   = 2\nOPC_START_FLASH = 3\nOPC_STOP_FLASH  = 4\nOPC_FLUSH       = 5\nOPC_START       = 6\nOPC_RESET       = 7\n\ncontrol_point_callback = (data, is_notification)->\n    raise \"Unexpected control point notification\"\n\ndefault_progress_callback = ->\n    raise \"Unexpected progress notification\"\n\nprogress_callback      = default_progress_callback\n\nscan_devices = (mac, cb)->\n    devices = {}\n    timer   = null\n\n    noble.on 'discover', ( peripheral )->\n        if BOOTLOADER_SERVICE_UUID in peripheral.advertisement.serviceUuids\n            if mac\n                if mac == peripheral.address\n                    clearTimeout timer\n                    cb(peripheral)\n            else\n                devices[ peripheral.id ] = peripheral\n\n    noble.on 'stateChange', ( state )->\n\n        if state == 'poweredOn'\n            timer = setTimeout (()->\n                    noble.stopScanning()\n                    if mac then cb(null) else cb(devices)\n                ), 3000\n\n            noble.startScanning []\n\nconnect_device = (peripheral, cb)->\n    peripheral.connect (error)->\n        if error\n            cb(null, error)\n        else\n            peripheral.discoverSomeServicesAndCharacteristics [BOOTLOADER_SERVICE_UUID], ALL_CHARACTERISTIC_UUIDS, ( error, services, characteristics )->\n                if ( error )\n                    console.log \"Error in discoverSomeServicesAndCharacteristics: #{error}\"\n                    cb(null, error)\n                else\n                    all = {}\n                    all[characteristic.uuid] = characteristic for characteristic in characteristics\n\n                    control_point_char  = all[CONTROL_POINT_UUID]\n                    data_char           = all[DATA_UUID]\n                    progress_char       = all[PROGRESS_UUID]\n\n                    control_point_char.on 'data', (data, is_notification)->\n                        control_point_callback( data, is_notification )\n\n                    progress_char.on 'data', (data, is_notification)->\n                        progress_callback( data, is_notification )\n\n                    control_point_char.notify true, (error)->\n                        if error\n                            cb(null, error)\n                        else\n                            progress_char.notify true, (error)->\n                                if error\n                                    cb(null, error)\n                                else\n                                    cb(peripheral, null)\n\nparse_control_point_response = (response_code, data, cb)->\n    expected_size = (size)->\n        if data.length != size\n            raise \"while parsing response (code=#{response_code}), the response expected to be #{size} in size, but was #{data.length}\"\n\n    switch response_code\n        when OPC_GET_VERSION\n            cb(null, data.toString())\n        when OPC_GET_CRC\n            expected_size 4\n            cb(null, data.readUInt32LE(0))\n        when OPC_GET_SIZES\n            expected_size 9\n            cb(null, data.readUInt8(0), data.readUInt32LE(1), data.readUInt32LE(5))\n        when OPC_START_FLASH\n            expected_size 5\n            cb(null, data.readUInt8(0), data.readUInt32LE(1))\n        when OPC_STOP_FLASH\n            expected_size 0\n            cb(null)\n        when OPC_FLUSH\n            expected_size 6\n            cb(null, data.readUInt32LE(0), data.readUInt16LE(4))\n        else\n            cb(\"invalid response code #{response_code}; expected #{opcode}\")\n\nPAD = '                                                                                                      '\n\nleft = (text, width)->\n    text = \"#{text}\"\n\n    if text.length > width\n        text.slice(0, width)\n    else\n        text + PAD.slice 0, width - text.length\n\nright = (text, width)->\n    text = \"#{text}\"\n\n    if text.length > width\n        text.slice(0, width)\n    else\n        PAD.slice( 0, width - text.length ) + text\n\nexecute = ( opcode, arg1, arg2 )->\n    cb     = if arguments.length == 2 then arg1 else arg2\n    params = if arguments.length == 2 then null else arg1\n\n    control_point_callback = (data)->\n        response_code = data.readUInt8()\n        data = data.slice 1\n\n        if response_code != opcode\n            cb(\"invalid response code #{response_code}; expected #{opcode}\")\n        else\n            parse_control_point_response response_code, data, cb\n\n    buffer = new Buffer( [ opcode ] )\n    buffer = Buffer.concat( [ buffer, params ] ) if params\n\n    control_point_char.write buffer, false, (error)->\n        if error\n            cb( error )\n\ndevice_address = ->\n    if !options['device']\n        console.log \"device address (--device) reqired!\"\n        process.exit 1\n\n    options['device']\n\nstart_address = ->\n    if !options['address']\n        console.log \"start address (--address) required!\"\n        process.exit 1\n\n    result = Number.parseInt options['address']\n\n    if isNaN result\n        console.log \"argument for start address (--address #{options['address']}) is not a number\"\n        process.exit 1\n\n    if result < 0\n        console.log \"argument for start address (--address #{options['address']}) is a negatic number\"\n        process.exit 1\n\n    result\n\nprint_usage = ->\n    console.log \"usage: ble_flash [options]\"\n    console.log \"options:\"\n    console.log \"  --help, -h                   this help\"\n    console.log \"  --address <addr>, -a <addr>  device start address if <input-file> is a binary file\"\n    console.log \"  --device <mac>, -d <mac>     48 bit MAC address of the device to be flashed\"\n    console.log \"  --version, -v                request version string from device\"\n    console.log \"  --list, -l                   scan for a list of bootloaders\"\n    console.log \"  --flash, -f <file>           flash the given file to the given address (--address)\"\n    console.log \"  --verbose, -V                a lot of debug printouts\"\n\ncalc_crc = ( data, start_address, size )->\n    42\n\naddress_to_buffer = (address, address_size)->\n    result = new Buffer( address_size )\n    for pos in [0...address_size]\n        result[ pos ] = address & 0xff\n        address = address / 256\n\n    result\n\nupload_range = ( peripheral, start_address, data, address_size, page_size, page_buffers, cb )->\n    console.log \"upload #{data.length} starting at: #{start_address}...\" if VERBOSE\n\n    data_on_the_fly   = 5\n    queued_data       = []\n\n    send_function = ->\n        while queued_data.length != 0 and data_on_the_fly != 0\n            data_on_the_fly = data_on_the_fly - 1\n            data = queued_data.shift()\n\n            data_char.write data, true, (error)->\n                data_on_the_fly = data_on_the_fly + 1\n\n                if error\n                    cb( error )\n                else\n                    send_function()\n\n    flash_cb = {\n        start_flash: ( start_address, cb ) ->\n            execute OPC_START_FLASH, new Buffer( start_address ), (error, mtu, checksum)->\n                console.log \"flash started. mtu: #{mtu}; checksum: #{checksum}\" if VERBOSE\n                cb(error, mtu, checksum)\n\n        send_data: ( data ) ->\n            queued_data.push data\n            send_function()\n\n        register_progress_callback: ( progress ) ->\n            progress_callback = ( data )->\n                if data.length != 7\n                    raise \"invalid progress PDU size #{data.length}\"\n\n                progress( data.readUInt32LE(0), data.readUInt16LE(4), data.readUInt8(6) )\n\n        flush: ( callback )->\n            execute OPC_FLUSH, callback\n\n        unregister_progress_callback: ->\n            progress_callback = default_progress_callback\n    }\n\n    new FlashMemory( flash_cb, start_address, data, address_size, page_size, page_buffers, cb )\n\nflash = ( file_name, start_address, peripheral, cb )->\n    console.log \"inquire bootloader buffer sizes...\" if VERBOSE\n\n    execute OPC_GET_SIZES, (error, address_size, page_size, page_buffers)->\n        raise \"#{device.address} #{version} Error: #{error}\" if error\n\n        console.log \"address_size: #{address_size}; page_size: #{page_size}, page_buffers: #{page_buffers}\" if VERBOSE\n\n        fs.readFile file_name, (error, data)->\n            raise \"Error reading input file #{file_name}\" if error\n\n            upload_range peripheral, start_address, data, address_size, page_size, page_buffers, cb\n\ntry\n    if options.help\n        print_usage()\n        process.exit 0\n\n    if options.list\n        console.log \" mac               | version              | addr. size | page size | buffers \"\n        console.log \"-----------------------------------------------------------------------------\"\n\n        print_line = (mac, version, address_size, page_size, page_buffer)->\n            console.log \" #{left mac, 17} | #{left version, 20} | #{right address_size, 10} | #{right page_size, 9} | #{right page_buffer, 7}\"\n\n        scan_devices null, (devices)->\n            number_of_devices = Object.keys(devices).length\n\n            if number_of_devices == 0\n                console.log \"no devices found.\"\n                process.exit 0\n\n            wait_for = number_of_devices\n            stop_waiting = ->\n                wait_for = wait_for - 1\n                process.exit 0 if wait_for == 0\n\n            for id, device of devices\n\n                connect_device device, (peripheral, error)->\n                    if error\n                        console.log \"#{device.address}: Error: #{error}\"\n                        stop_waiting()\n                    else\n                        execute OPC_GET_VERSION, (error, version)->\n                            if error\n                                console.log \"#{device.address} Error: #{error}\"\n                                stop_waiting()\n                            else\n                                execute OPC_GET_SIZES, (error, address_size, page_size, page_buffer)->\n                                    if error\n                                        console.log \"#{device.address} #{version} Error: #{error}\"\n                                    else\n                                        print_line device.address, version, address_size, page_size, page_buffer\n                                        peripheral.disconnect()\n                                        stop_waiting()\n\n    else if options.version\n        scan_devices device_address(), (device)->\n            raise \"device not found!\" if !device\n\n            connect_device device, (peripheral, error)->\n                raise \"#{device.address}: Error: #{error}\" if error\n\n                execute OPC_GET_VERSION, (error, version)->\n                    raise \"error requesting version string: #{error}\" if error\n\n                    console.log version\n                    process.exit 0\n\n    else if options.flash\n        console.log \"start flashing #{options.flash} at 0x#{start_address().toString(16)} to device #{device_address()}\"\n\n        scan_devices device_address(), (device)->\n            raise \"device not found!\" if !device\n\n            console.log \"device found...\"\n\n            connect_device device, (peripheral, error)->\n                raise \"connecting #{device.address}: Error: #{error}\" if error\n\n                console.log \"device connected.\" if VERBOSE\n\n                flash options.flash, start_address(), device, (error)->\n                    raise \"flashing device: Error: #{error}\" if error\n\n                    console.log \"device successfully flashed\"\n                    process.exit 0\n\n\n    else\n        console.log \"Unrecognized command.\"\n        print_usage()\n        process.exit 1\n\ncatch error\n    console.log error\n    process.exit 1\n"
  },
  {
    "path": "examples/ble_flash/crc.coffee",
    "content": "exports.buf = (()->\n    crcTable = (()->\n        crcTable = []\n\n        for n in [ 0...256 ]\n            c = n\n\n            for k in [ 0...8 ]\n                c = if ( c & 1 ) != 0 then (0xEDB88320 ^ (c >>> 1)) else (c >>> 1)\n\n            crcTable[n] = c\n\n        crcTable\n    )()\n\n    ( data, crc = 0 )->\n        crc = crc ^ (-1)\n\n        for i in [ 0...data.length ]\n            crc = (crc >>> 8) ^ crcTable[ ( crc ^ data[ i ] ) & 0xFF]\n\n        result = (crc ^ (-1))\n\n        if result < 0 then 0x100000000 + result else result\n)()"
  },
  {
    "path": "examples/ble_flash/crc_tests.coffee",
    "content": "expect  = require( 'chai' ).expect\nassert  = require 'assert'\ncrc     = require './crc.coffee'\n\ndescribe 'crc', ->\n    it 'calculating crc in two parts results in same result', ->\n        buffer = new Buffer [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ]\n        expect( crc.buf( buffer.slice( 5 ), crc.buf( buffer.slice( 0, 5 ) ) ) ).to.equal crc.buf( buffer )\n\n    it 'caculates a specific value for the test input', ->\n        buffer = new Buffer [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ]\n        expect( crc.buf( buffer ) ).to.equal 0x40EFAB9E\n"
  },
  {
    "path": "examples/ble_flash/flash.coffee",
    "content": "crc32 = require './crc.coffee'\n\nTIMEOUT_MS       = 500\n\nclass FlashRange\n    ###\n     @peripheral ble abstraction expected to have following functions\n       start_flash( start_address, callback(error, mtu, checksum) )\n       send_data( data )\n       flush( callback( error, checksum, consecutive ) )\n       register_progress_callback(callback(checksum, consecutive, mtu))\n       unregister_progress_callback(callback)\n     @start_address address to flash the data on the target\n     @data Buffer containing the data to be flashed\n     @address_size size of an address on the target in bytes\n     @page_size size of flash page on the target in bytes\n     @page_buffer number of page buffers within the targets bootloader\n     @cb callback to be called, when the flashing is done or when an error occured\n    ###\n    constructor: (@peripheral, @start_address, @data, @address_size, @page_size, @page_buffer, @cb)->\n        timer           = null\n        calc_checksum   = null\n        capacity        = @page_size * @page_buffer\n\n        if @start_address % @page_size != 0\n            capacity        = capacity - ( @start_address % @page_size )\n\n        data_checksums  = []\n        consecutive     = 0\n\n        send_data = ( that, mtu )->\n            while that.data.length > 0 && capacity > 0\n                send_size = Math.min( mtu - 3, that.data.length, capacity )\n                new_data  = that.data.slice( 0, send_size )\n\n                that.peripheral.send_data( new_data )\n\n                # if this is the last chunk of a page, that page will be freed again, if the bootloader\n                # reports progress behind this chunk.\n                if Math.floor( ( capacity - 1 ) % that.page_size ) + 1 <= send_size\n                    length_till_block_end   = capacity % that.page_size\n\n                    block_checksum = crc32.buf new_data.slice( 0, length_till_block_end ), calc_checksum\n                    data_checksums.push [ consecutive, block_checksum ]\n                    consecutive    = consecutive + 1\n\n                that.data   = that.data.slice send_size\n                capacity    = capacity - send_size\n\n                calc_checksum  = crc32.buf new_data, calc_checksum\n\n        check_progress_checksum = ( checksum, consecutive )->\n            if data_checksums.length > 0\n                [ con, crc_calculated ] = data_checksums.shift()\n\n                if con == consecutive && crc_calculated == checksum\n                    return true\n\n            false\n\n        flush_callback = ( that )->\n            ( error, checksum, con )->\n                if error\n                    that.cb( error )\n                else\n                    if calc_checksum != checksum || consecutive != con\n                        that.cb 'checksum error in flush response'\n                    else\n                        that.cb()\n\n        progress_callback = (that)->\n            (checksum, con, mtu )->\n                if !check_progress_checksum( checksum, con )\n                    that.cb 'checksum error in progress'\n                else\n                    capacity = capacity + that.page_size\n\n                    if that.data.length > 0\n                        send_data(that, mtu, capacity)\n                    else\n                        if data_checksums.length == 0\n                            if capacity == that.page_size * that.page_buffer\n                                that.cb()\n                            else\n                                that.peripheral.flush flush_callback( that )\n\n        start_flash_handler = (that)->\n            (error, mtu, checksum)->\n                clearTimeout that.timer\n\n                if error\n                    that.cb( error )\n                else\n                    if checksum == calc_checksum\n                        send_data(that, mtu, capacity)\n                    else\n                        that.cb 'checksum error'\n\n        address = []\n        for [0...@address_size]\n            address.push @start_address & 0xff\n            @start_address = @start_address / 256\n\n        calc_checksum = crc32.buf address\n\n        @peripheral.register_progress_callback progress_callback( @ )\n\n        @timer = setTimeout( ( (that) ->\n            -> that.cb(\"Timeout waiting for flash progress\")\n            )(@), TIMEOUT_MS )\n\n        @peripheral.start_flash address, start_flash_handler( @ )\n\n\nexports.FlashMemory = FlashRange\n"
  },
  {
    "path": "examples/ble_flash/flash_tests.coffee",
    "content": "expect  = require( 'chai' ).expect\nassert  = require 'assert'\nsinon   = require 'sinon'\nflash   = require './flash.coffee'\nutil    = require 'util'\ncrc     = require './crc.coffee'\n\ncreate_network_mock = ( data_cb )->\n    {\n        start_flash: sinon.spy(),\n        send_data: if data_cb then data_cb else sinon.spy(),\n        flush: sinon.spy()\n        register_progress_callback: sinon.spy()\n    }\n\ncollect_data_send = ( network )->\n    send_data = network.send_data\n    result    = new Buffer(0)\n\n    for n in [ 0...send_data.callCount ]\n        result = Buffer.concat([result, send_data.getCall(n).args[0]])\n\n    result\n\nrandom_buffer = ( size )->\n    result = new Buffer size\n\n    result[n] = Math.floor(Math.random() * 255) for n in [0...size]\n    result\n\nlast_data_being_send = ( network_mock )->\n    network_mock.send_data.lastCall.args[ 0 ]\n\ndescribe 'Network-Mock', ->\n    network = null\n\n    beforeEach ->\n        network = create_network_mock()\n\n    it 'implements start_flash', ->\n        network.start_flash()\n\n    it 'reports start_flash beeing called', ->\n        network.start_flash()\n        assert( network.start_flash.calledOnce )\n\ndescribe 'FlashMemory', ->\n\n    # c'tor parameters to FlashMemory\n    network             = null\n    start_address       = 0x12345678\n    data                = random_buffer( 3 * 1024 )\n    address_size        = 4\n    page_size           = 1024\n    page_buffers        = 3\n    error_callback      = null\n    mtu                 = 42\n    receive_capacity    = page_size * page_buffers\n\n    clock           = null\n\n    beforeEach ->\n        network         = create_network_mock()\n        clock           = sinon.useFakeTimers()\n        error_callback  = sinon.spy()\n\n    afterEach ->\n        clock.restore()\n\n    describe 'start flashing', ->\n\n        beforeEach ->\n            new flash.FlashMemory network, start_address, data, address_size, page_size, page_buffers, error_callback\n\n        it 'should start to flash once', ->\n            assert( network.start_flash.calledOnce )\n\n        it 'should send the start address with the address_size', ->\n            expect( network.start_flash.getCall( 0 ).args[ 0 ] ).to.deep.equal [ 0x78, 0x56, 0x34, 0x12 ]\n\n        it 'should pass a callback as second parameter', ->\n            expect( network.start_flash.getCall( 0 ).args.length ).to.equal 2\n\n        it 'should anticipate errors', ->\n            network.start_flash.getCall( 0 ).args[ 1 ]( \"something got wrong\" )\n            expect( error_callback.getCall( 0 ).args[ 0 ] ).to.equal \"something got wrong\"\n\n        it 'no errors no callback called', ->\n            expect( error_callback.callCount ).to.equal 0\n\n        it 'does not call send_data before the end of the procedure', ->\n            expect( network.send_data.callCount ).to.equal 0\n\n        describe 'start flashing have an 6 byte address length', ->\n\n            beforeEach ->\n                network         = create_network_mock()\n                start_address   = 0x123456789abc\n                address_size    = 6\n\n                new flash.FlashMemory network, start_address, data, address_size, page_size, page_buffers, error_callback\n\n            it 'should send the start address with the address_size', ->\n                expect( network.start_flash.getCall( 0 ).args[ 0 ] ).to.deep.equal(\n                    [ 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12 ])\n\n    describe 'running in a timeout', ->\n        beforeEach ->\n            new flash.FlashMemory network, start_address, data, address_size, page_size, page_buffers, error_callback\n            clock.tick 1000\n\n        it 'will call the error callback', (done)->\n            assert( error_callback.calledOnce )\n            done()\n\n    describe 'after receiving the start_address procedure result', ->\n\n        beforeEach ->\n            network         = create_network_mock()\n            start_address   = 0x12345678\n            address_size    = 4\n\n        checksum = crc.buf [ 0x78, 0x56, 0x34, 0x12 ]\n\n        beforeEach ->\n            new flash.FlashMemory network, start_address, data, address_size, page_size, page_buffers, error_callback\n            network.start_flash.lastCall.args[ 1 ]( null, mtu, checksum )\n\n        it 'starts sending data', ->\n            expect( network.send_data.callCount ).to.not.equal 0\n\n        it 'data size is MTU -3 ', ->\n            expect( network.send_data.firstCall.args[ 0 ].length ).to.equal( mtu - 3 )\n\n    describe 'after receiving the start_address procedure response with a wrong crc', ->\n\n        beforeEach ->\n            new flash.FlashMemory network, start_address, data, address_size, page_size, page_buffers, error_callback\n            network.start_flash.lastCall.args[ 1 ]( null, mtu, 0xdeadbeef )\n\n        it 'calls the error callback', ->\n            assert( error_callback.calledOnce )\n            expect( error_callback.lastCall.args[ 0 ] ).to.equal 'checksum error'\n\n    describe 'sending data', ->\n\n        beforeEach ->\n            data          = random_buffer( receive_capacity + page_size )\n            address_size  = 4\n            mtu           = 42\n\n        describe 'start address equal to a page address', ->\n\n            beforeEach ->\n                start_address = 3 * page_size\n                checksum      = crc.buf [ 0x00, 0x0C, 0x00, 0x00 ]\n\n                new flash.FlashMemory network, start_address, data, address_size, page_size, page_buffers, error_callback\n                network.start_flash.lastCall.args[ 1 ]( null, mtu, checksum )\n\n            it 'should not call the error_callback', ->\n                expect( error_callback.callCount ).to.equal 0\n\n            it 'should send data up to the receive capacity', ->\n                expect( collect_data_send( network ).length ).to.equal receive_capacity\n\n            it 'should send the first data', ->\n                expect( collect_data_send( network ) ).to.deep.equal( data.slice( 0, receive_capacity ) )\n\n        describe 'start address not beeign equal to a page address', ->\n\n            checksum    = null\n\n            beforeEach ->\n                start_address   = 3 * page_size + 0x123\n                checksum        = crc.buf [ 0x23, 0x0D, 0x00, 0x00 ]\n                receive_capacity= page_size * ( page_buffers - 1 ) + ( page_size - 0x123 )\n\n                new flash.FlashMemory network, start_address, data, address_size, page_size, page_buffers, error_callback\n                network.start_flash.lastCall.args[ 1 ]( null, mtu, checksum )\n\n            it 'should not call the error_callback', ->\n                expect( error_callback.callCount ).to.equal 0\n\n            it 'should send data up to the receive capacity', ->\n                expect( collect_data_send( network ).length ).to.equal receive_capacity\n\n            it 'should send the first data', ->\n                expect( collect_data_send( network ) ).to.deep.equal( data.slice( 0, receive_capacity ) )\n\n            it 'sends more data when progress indicates a freed block received', ->\n                # Simulate that the bootloader sends a progress message, right after the first page\n                data_send = collect_data_send( network )\n                checksum  = crc.buf data_send.slice( 0, ( page_size - 0x123 ) ), checksum\n\n                progress_callback = network.register_progress_callback.lastCall.args[ 0 ]\n                progress_callback( checksum, 0, mtu )\n\n                expect( error_callback.called ).to.be.false\n                expect( collect_data_send( network ).length ).to.be.least data_send.length\n\n        describe 'writeing just a part of a page', ->\n\n            checksum = 0\n\n            beforeEach ->\n                start_address   = 3 * page_size\n                checksum        = crc.buf [ 0x00, 0x0C, 0x00, 0x00 ]\n                data            = random_buffer( 42 )\n\n                new flash.FlashMemory network, start_address, data, address_size, page_size, page_buffers, error_callback\n\n                start_flash_callback = network.start_flash.lastCall.args[ 1 ]\n                start_flash_callback( null, mtu, checksum )\n\n            describe 'start address equal to a page address', ->\n\n                it 'should send the data', ->\n                    expect( collect_data_send( network ) ).to.deep.equal( data )\n\n                it 'should wait for a handshake', ->\n                    expect( error_callback.called ).to.be.false\n                    network.register_progress_callback.lastCall.args[ 0 ](checksum, 0, mtu )\n                    expect( error_callback.called ).to.be.true\n\n    describe 'receiving progress', ->\n        beforeEach ->\n            data          = random_buffer( 3 * receive_capacity )\n            address_size  = 4\n            mtu           = 42\n\n        describe 'fails when', ->\n\n            beforeEach ->\n                start_address = 3 * page_size\n                checksum      = crc.buf [ 0x00, 0x0C, 0x00, 0x00 ]\n\n                new flash.FlashMemory network, start_address, data, address_size, page_size, page_buffers, error_callback\n\n                start_flash_callback = network.start_flash.lastCall.args[ 1 ]\n                start_flash_callback( null, mtu, checksum )\n\n            it 'checksum error is detected', ->\n                consecutive = 3\n                expect( error_callback.called ).to.be.false\n\n                progress_callback = network.register_progress_callback.lastCall.args[ 0 ]\n                progress_callback( 0xdeadbeef, consecutive, mtu )\n\n                expect( error_callback.called ).to.be.true\n\n    describe 'continously reveiving progress', ->\n\n        checksum      = null\n\n        beforeEach ->\n            receive_capacity = page_size * page_buffers\n            network          = create_network_mock()\n            data             = random_buffer( 3 * receive_capacity )\n            address_size     = 4\n            mtu              = 42\n\n            start_address    = 3 * page_size\n            checksum         = crc.buf [ 0x00, 0x0C, 0x00, 0x00 ]\n\n            new flash.FlashMemory network, start_address, data, address_size, page_size, page_buffers, error_callback\n\n            start_flash_callback = network.start_flash.lastCall.args[ 1 ]\n            start_flash_callback( null, mtu, checksum )\n\n        it 'sends data until receive capacity is reached', ->\n            expect( collect_data_send( network ).length ).to.equal receive_capacity\n\n        it 'sends more data when progress indicates a freed block received', ->\n            # Simulate that the bootloader sends a progress message, right after the first page\n            data_send = collect_data_send( network )\n\n            checksum  = crc.buf data_send.slice( 0, page_size ), checksum\n\n            progress_callback = network.register_progress_callback.lastCall.args[ 0 ]\n            progress_callback( checksum, 0, mtu )\n\n            expect( error_callback.called ).to.be.false\n            expect( collect_data_send( network ).length ).to.be.least receive_capacity + page_size\n\n        it 'sends new data with the new mtu size', ->\n            # Simulate that the bootloader sends a progress message, right after the first page\n            data_send = collect_data_send( network )\n\n            checksum  = crc.buf data_send.slice( 0, page_size ), checksum\n            new_mtu   = mtu - 4\n\n            progress_callback = network.register_progress_callback.lastCall.args[ 0 ]\n            progress_callback( checksum, 0, new_mtu )\n\n            send_data = network.send_data\n            expect( send_data.getCall( send_data.callCount - 2 ).args[0].length ).to.equal new_mtu - 3\n\n        it 'indicates error when progress indicates all data received at once', ->\n            # Simulate that the bootloader sends a progress message, right after the first page\n            data_send = collect_data_send( network )\n\n            checksum  = crc.buf data_send, checksum\n\n            progress_callback = network.register_progress_callback.lastCall.args[ 0 ]\n            progress_callback( checksum, 2, mtu )\n\n            expect( error_callback.called ).to.be.true\n\n    describe 'end of flash', ->\n\n        checksum          = null\n        progress_callback = null\n        consecutive       = null\n\n        beforeEach ->\n            page_buffers     = 2\n            receive_capacity = page_size * page_buffers\n            network          = create_network_mock()\n            data             = random_buffer( 2 * receive_capacity )\n            address_size     = 3\n            mtu              = 42\n            consecutive      = 0\n\n            start_address    = 3 * page_size\n            checksum         = crc.buf [ 0x00, 0x0C, 0x00 ]\n\n            new flash.FlashMemory network, start_address, data, address_size, page_size, page_buffers, error_callback\n\n            start_flash_callback = network.start_flash.lastCall.args[ 1 ]\n            start_flash_callback( null, mtu, checksum )\n\n            progress_callback = network.register_progress_callback.lastCall.args[ 0 ]\n\n        progress_for_next_buffer = ->\n            data_send = collect_data_send( network )\n\n            checksum  = crc.buf data_send.slice( consecutive * page_size, ( consecutive + 1 ) * page_size ), checksum\n\n            progress_callback( checksum, consecutive, mtu )\n\n            consecutive = consecutive + 1\n\n        it 'does not send indicates the end of flash, after sending all data', ->\n            progress_for_next_buffer()\n            progress_for_next_buffer()\n            progress_for_next_buffer()\n\n            expect( error_callback.called ).to.be.false\n            expect( collect_data_send( network ).length ).to.be.least data.length\n\n        it 'callback called, after all data was received', ->\n            for [ 0...4 ]\n                progress_for_next_buffer()\n\n            expect( error_callback.called ).to.be.true\n            expect( error_callback.lastCall.args[ 0 ] ).to.not.exist\n\n    describe 'flashing not full block', ->\n        checksum          = null\n        progress_callback = null\n        consecutive       = null\n\n        beforeEach ->\n            page_buffers     = 2\n            receive_capacity = page_size * page_buffers\n            network          = create_network_mock()\n            data             = random_buffer( 2 * receive_capacity - 1 )\n            address_size     = 3\n            mtu              = 42\n            consecutive      = 0\n\n            start_address    = 3 * page_size\n            checksum         = crc.buf [ 0x00, 0x0C, 0x00 ]\n\n            new flash.FlashMemory network, start_address, data, address_size, page_size, page_buffers, error_callback\n\n            start_flash_callback = network.start_flash.lastCall.args[ 1 ]\n            start_flash_callback( null, mtu, checksum )\n\n            progress_callback = network.register_progress_callback.lastCall.args[ 0 ]\n\n        progress_for_next_buffer = ->\n            data_send = collect_data_send( network )\n\n            checksum  = crc.buf data_send.slice( consecutive * page_size, ( consecutive + 1 ) * page_size ), checksum\n\n            progress_callback( checksum, consecutive, mtu )\n\n            consecutive = consecutive + 1\n\n        it 'does not call flush if not the last full buffer was flushed', ->\n            progress_for_next_buffer()\n            progress_for_next_buffer()\n\n            expect( error_callback.called ).to.be.false\n            expect( network.flush.called ).to.be.false\n\n        it 'calls flush if the last full buffer was flushed', ->\n            progress_for_next_buffer()\n            progress_for_next_buffer()\n            progress_for_next_buffer()\n\n            expect( error_callback.called ).to.be.false\n            expect( network.flush.called ).to.be.true\n\n            data_send = collect_data_send( network )\n            expect( data_send ).to.deep.equal data\n\n        it 'error in flush response is anticipated', ->\n            progress_for_next_buffer()\n            progress_for_next_buffer()\n            progress_for_next_buffer()\n\n            flash_callback = network.flush.lastCall.args[ 0 ]\n            flash_callback \"error!!!!111\"\n\n            expect( error_callback.called ).to.be.true\n            expect( error_callback.lastCall.args[ 0 ] ).to.equal \"error!!!!111\"\n\n        it 'crc error in flush response is anticipated', ->\n            progress_for_next_buffer()\n            progress_for_next_buffer()\n            progress_for_next_buffer()\n\n            flash_callback = network.flush.lastCall.args[ 0 ]\n            flash_callback( null, 0x12345678, 3 )\n\n            expect( error_callback.called ).to.be.true\n            expect( error_callback.lastCall.args[ 0 ] ).to.equal 'checksum error in flush response'\n\n        it 'callback called after flush response', ->\n            progress_for_next_buffer()\n            progress_for_next_buffer()\n            progress_for_next_buffer()\n\n            checksum  = crc.buf data.slice( consecutive * page_size, ( consecutive + 1 ) * page_size ), checksum\n\n            flash_callback = network.flush.lastCall.args[ 0 ]\n            flash_callback( null, checksum, 3 )\n\n            expect( error_callback.called ).to.be.true\n            expect( error_callback.lastCall.args[ 0 ] ).to.not.exist\n"
  },
  {
    "path": "examples/blinky.cpp",
    "content": "/**\n * @example blinky.cpp\n *\n * This example shows, how to implement a very simple GATT server that\n * provides one service to switch an LED.\n *\n * The example servers only characteristic requires encryption. By default,\n * the server implements only LESC pairing. Bonding is not implemented in\n * this example.\n */\n\n#include <bluetoe/server.hpp>\n#include <bluetoe/device.hpp>\n\n#include \"resources.hpp\"\n\nstatic examples::led output;\n\nusing namespace bluetoe;\n\nstatic std::uint8_t io_pin_write_handler( bool state )\n{\n    output.value( state );\n\n    return error_codes::success;\n}\n\nusing blinky_server = server<\n    service<\n        service_uuid< 0xC11169E1, 0x6252, 0x4450, 0x931C, 0x1B43A318783B >,\n        characteristic<\n            requires_encryption,\n            free_write_handler< bool, io_pin_write_handler >\n        >\n    >,\n    max_mtu_size< 65 >\n>;\n\ndevice<\n    blinky_server,\n    link_layer::buffer_sizes< 200, 200 >\n> gatt_srv;\n\nint main()\n{\n    for ( ;; )\n        gatt_srv.run();\n}\n"
  },
  {
    "path": "examples/blinky_with_lesc_and_legacy_pairing.cpp",
    "content": "/**\n * @example blinky_with_lesc_and_legacy_pairing.cpp\n *\n * This example shows, how to implement a very simple GATT server that\n * provides one service to switch an LED.\n *\n * The example servers only characteristic requires encryption. This server\n * supoorts legacy parining and LESC pairing. Bonding is not implemented in\n * this example.\n */\n\n#include <bluetoe/server.hpp>\n#include <bluetoe/device.hpp>\n\n#include \"resources.hpp\"\n\nstatic examples::led output;\n\nusing namespace bluetoe;\n\nstatic std::uint8_t io_pin_write_handler( bool state )\n{\n    output.value( state );\n\n    return error_codes::success;\n}\n\nusing blinky_server = server<\n    service<\n        service_uuid< 0xC11169E1, 0x6252, 0x4450, 0x931C, 0x1B43A318783B >,\n        characteristic<\n            requires_encryption,\n            free_write_handler< bool, io_pin_write_handler >\n        >\n    >,\n    max_mtu_size< 65 >\n>;\n\ndevice<\n    blinky_server,\n    security_manager,\n    link_layer::buffer_sizes< 200, 200 > > gatt_srv;\n\nint main()\n{\n    for ( ;; )\n        gatt_srv.run();\n}\n"
  },
  {
    "path": "examples/blinky_with_oob.cpp",
    "content": "/**\n * @example blinky_with_oob.cpp\n *\n * This example shows, how to implement a very simple GATT server that\n * provides one service to switch an LED.\n *\n * The example servers only characteristic requires encryption. This server\n * implements pairing by using an Out of Band key. Bonding is not implemented in\n * this example.\n */\n\n#include <bluetoe/server.hpp>\n#include <bluetoe/device.hpp>\n\n#include \"resources.hpp\"\n\nstatic examples::led output;\n\nusing namespace bluetoe;\n\nstatic std::uint8_t io_pin_write_handler( bool state )\n{\n    output.value( state );\n\n    return error_codes::success;\n}\n\nusing blinky_server = server<\n    service<\n        service_uuid< 0xC11169E1, 0x6252, 0x4450, 0x931C, 0x1B43A318783B >,\n        characteristic<\n            requires_encryption,\n            free_write_handler< bool, io_pin_write_handler >\n        >\n    >,\n    max_mtu_size< 65 >\n>;\n\nstruct oob_cb_t {\n    std::pair< bool, std::array< std::uint8_t, 16 > > sm_oob_authentication_data(\n        const bluetoe::link_layer::device_address& /* address */ )\n    {\n        return { true, std::array< std::uint8_t, 16 >{{\n            0xF1, 0x50, 0xA0, 0xAE,\n            0xB7, 0xAA, 0xBA, 0xC8,\n            0x19, 0x22, 0xB6, 0x15,\n            0x4C, 0x23, 0x94, 0x7A\n        }} };\n    }\n\n} oob_cb;\n\ndevice<\n    blinky_server,\n    link_layer::buffer_sizes< 200, 200 >,\n    legacy_security_manager, // use one of legacy_security_manager, lesc_security_manager or security_manager\n    oob_authentication_callback< oob_cb_t, oob_cb >\n> gatt_srv;\n\nint main()\n{\n    for ( ;; )\n        gatt_srv.run();\n}\n"
  },
  {
    "path": "examples/blinky_without_encryption.cpp",
    "content": "/**\n * @example blinky_without_encryption.cpp\n *\n * This example shows, how to implement a very simple GATT server that\n * provides one service to switch an LED.\n *\n * The example servers does not require encryption, which automatically results\n * in Bluetoe dropping any support for encryption / pairing.\n */\n\n#include <bluetoe/server.hpp>\n#include <bluetoe/device.hpp>\n\n#include \"resources.hpp\"\n\nstatic examples::led output;\n\nusing namespace bluetoe;\n\nstatic std::uint8_t io_pin_write_handler( bool state )\n{\n    output.value( state );\n\n    return error_codes::success;\n}\n\nusing blinky_server = server<\n    service<\n        service_uuid< 0xC11169E1, 0x6252, 0x4450, 0x931C, 0x1B43A318783B >,\n        characteristic<\n            free_write_handler< bool, io_pin_write_handler >\n        >\n    >\n>;\n\ndevice< blinky_server > gatt_srv;\n\nint main()\n{\n    for ( ;; )\n        gatt_srv.run();\n}"
  },
  {
    "path": "examples/bootloader.cpp",
    "content": "#include <bluetoe/server.hpp>\n#include <bluetoe/device.hpp>\n#include <bluetoe/services/bootloader.hpp>\n#include <bluetoe/connection_event_callback.hpp>\n#include <nrf.h>\n\nstatic constexpr std::size_t    flash_page_size    = 1024;\nstatic constexpr unsigned       erase_page_time_ms = 100;\nstatic constexpr unsigned       number_of_concurrent_flashs = 2;\nstatic constexpr std::uint16_t  min_connection_interval = erase_page_time_ms;\n\nnamespace bb = bluetoe::bootloader;\n\nclass flash_handler {\npublic:\n    bb::error_codes start_flash( std::uintptr_t address, const std::uint8_t* values, std::size_t size );\n    bb::error_codes run( std::uintptr_t start_addr );\n    bb::error_codes reset();\n    std::pair< const std::uint8_t*, std::size_t > get_version();\n    void read_mem( std::uintptr_t address, std::size_t size, std::uint8_t* destination );\n    std::uint32_t checksum32( std::uintptr_t start_addr, std::size_t size );\n    std::uint32_t checksum32( const std::uint8_t* start_addr, std::size_t size, std::uint32_t old_crc );\n    std::uint32_t checksum32( std::uintptr_t start_addr );\n    bb::error_codes public_read_mem( std::uintptr_t address, std::size_t size, std::uint8_t* destination );\n    std::uint32_t public_checksum32( std::uintptr_t start_addr, std::size_t size );\n    void control_point_notification_call_back();\n    void data_indication_call_back();\n\n    flash_handler();\n\n    void ll_connection_event_happend();\n\n    template < typename ConnectionData >\n    void ll_connection_established(\n             const bluetoe::link_layer::connection_details&   details,\n             const bluetoe::link_layer::connection_addresses& addresses,\n             const ConnectionData&                            connection );\n\n    template < typename ConnectionData >\n    void ll_connection_changed(\n             const bluetoe::link_layer::connection_details&  details,\n             const ConnectionData&                           connection );\n\n    template < typename ConnectionData >\n    void ll_connection_closed( std::uint8_t reason, const ConnectionData& connection );\n\nprivate:\n    std::uint32_t crc_table_[ 256 ];\n\n    struct flash_queue_entry {\n        std::uintptr_t      address;\n        const std::uint8_t* values;\n    };\n\n    std::array< flash_queue_entry, number_of_concurrent_flashs > flash_entries_;\n    unsigned        next_flash_entry_;\n    unsigned        num_flash_entries_;\n    std::uint16_t   current_connection_interval_;\n    bool            connection_interval_update_running_;\n};\n\nusing gatt_definition = bluetoe::server<\n    bluetoe::bootloader_service<\n        bb::handler< flash_handler >,\n        bb::page_size< flash_page_size >,\n        bb::white_list<\n            bb::memory_region< 0x6000, 0x40000 >\n        >\n    >,\n    bluetoe::peripheral_connection_interval_range< min_connection_interval >\n>;\n\n/*\n * Change the default device address slightly, so that clients do not get confused by devices that\n * have the very same address, but totally different GATT structures\n */\nstruct address_generator {\n    static constexpr bool is_random()\n    {\n        return true;\n    }\n\n    template < class Radio >\n    static bluetoe::link_layer::random_device_address address( const Radio& r )\n    {\n        return bluetoe::link_layer::address::generate_static_random_address( ~r.static_random_address_seed() );\n    }\n\n    struct meta_type :\n        bluetoe::link_layer::details::device_address_meta_type,\n        bluetoe::link_layer::details::valid_link_layer_option_meta_type {};\n};\n\ngatt_definition gatt_server;\n\nbluetoe::device<\n    gatt_definition,\n    bluetoe::link_layer::buffer_sizes< flash_page_size * 3, flash_page_size * 3 >,\n    bluetoe::link_layer::connection_event_callback< gatt_definition, gatt_server, erase_page_time_ms >,\n    bluetoe::link_layer::connection_callbacks< gatt_definition, gatt_server >,\n    bluetoe::l2cap::signaling_channel<>,\n    address_generator\n> link_layer;\n\nint main()\n{\n    for ( ;; )\n    {\n        link_layer.run();\n    }\n}\n\nbb::error_codes flash_handler::start_flash( std::uintptr_t address, const std::uint8_t* values, std::size_t size )\n{\n    assert( num_flash_entries_ < number_of_concurrent_flashs );\n    assert( size == flash_page_size );\n    static_cast<void>(size);\n\n    const auto next_entry = ( num_flash_entries_ + next_flash_entry_ ) % number_of_concurrent_flashs;\n    flash_entries_[ next_entry ] = flash_queue_entry{ address, values };\n\n    ++num_flash_entries_;\n\n    // if the connection interval is so small, that the ll_connection_event_happend() will never be called\n    // we try to ask the central to change the connection parameters.\n    if ( current_connection_interval_ < min_connection_interval && !connection_interval_update_running_ )\n    {\n        connection_interval_update_running_ = link_layer.connection_parameter_update_request(\n            min_connection_interval, 2 * min_connection_interval, 0, min_connection_interval );\n    }\n\n    return bb::error_codes::success;\n}\n\nbb::error_codes flash_handler::run( std::uintptr_t )\n{\n    return bb::error_codes::success;\n}\n\nbb::error_codes flash_handler::reset()\n{\n    return bb::error_codes::success;\n}\n\nstd::pair< const std::uint8_t*, std::size_t > flash_handler::get_version()\n{\n    static const std::uint8_t version[] = \"ble_flash 1.0\";\n\n    return std::pair< const std::uint8_t*, std::size_t >( &version[ 0 ], sizeof( version ) -1 );\n}\n\nvoid flash_handler::read_mem( std::uintptr_t, std::size_t, std::uint8_t* )\n{\n}\n\nstd::uint32_t flash_handler::checksum32( std::uintptr_t start_addr, std::size_t size )\n{\n    return checksum32( reinterpret_cast< const std::uint8_t* >( start_addr ), size, 0 );\n}\n\nstd::uint32_t flash_handler::checksum32( const std::uint8_t* data, std::size_t size, std::uint32_t crc )\n{\n    crc = ~crc;\n\n    for ( ; size; --size, ++data )\n        crc = (crc >> 8) ^ crc_table_[ ( crc ^ *data ) & 0xFF ];\n\n    return ~crc;\n}\n\nstd::uint32_t flash_handler::public_checksum32( std::uintptr_t start_addr, std::size_t size )\n{\n    return checksum32( start_addr, size );\n}\n\nstd::uint32_t flash_handler::checksum32( std::uintptr_t start_addr )\n{\n    std::uint8_t addr[ sizeof( start_addr ) ];\n\n    for ( auto p = std::begin( addr ); p != std::end( addr ); ++p, start_addr = start_addr >> 8 )\n        *p = start_addr & 0xff;\n\n    return checksum32( std::begin( addr ), sizeof( addr ), 0 );\n}\n\nbb::error_codes flash_handler::public_read_mem( std::uintptr_t address, std::size_t size, std::uint8_t* destination )\n{\n    read_mem( address, size, destination );\n\n    return bb::error_codes::success;\n}\n\nvoid flash_handler::control_point_notification_call_back()\n{\n    gatt_server.bootloader_control_point_notification( gatt_server );\n}\n\nvoid flash_handler::data_indication_call_back()\n{\n    gatt_server.bootloader_data_indication( gatt_server );\n}\n\nflash_handler::flash_handler()\n    : next_flash_entry_( 0 )\n    , num_flash_entries_( 0 )\n    , current_connection_interval_( 0 )\n    , connection_interval_update_running_( false )\n{\n    for ( std::uint32_t n = 0; n != sizeof( crc_table_ ) / sizeof( crc_table_[ 0 ] ); ++n )\n    {\n        std::uint32_t c = n;\n\n        for ( std::uint32_t k = 0; k != 8; ++k )\n            c = ( c & 1 )\n                ? (0xEDB88320 ^ (c >> 1))\n                : (c >> 1);\n\n        crc_table_[ n ] = c;\n    }\n}\n\nvoid wait_flash()\n{\n    while ( ( NRF_NVMC->READY & NVMC_READY_READY_Ready ) == 0 )\n        ;\n}\n\nstatic void erase_flash( std::uintptr_t addr )\n{\n    NRF_NVMC->CONFIG = ( NRF_NVMC->CONFIG & ~NVMC_CONFIG_WEN_Msk ) | NVMC_CONFIG_WEN_Een;\n\n    NRF_NVMC->ERASEPAGE = static_cast< std::uint32_t >( addr );\n\n    wait_flash();\n\n    NRF_NVMC->CONFIG = ( NRF_NVMC->CONFIG & ~NVMC_CONFIG_WEN_Msk );\n}\n\nstatic void flash_page( std::uintptr_t addr, const std::uint8_t* page )\n{\n    wait_flash();\n\n    NRF_NVMC->CONFIG = ( NRF_NVMC->CONFIG & ~NVMC_CONFIG_WEN_Msk ) | NVMC_CONFIG_WEN_Wen;\n    wait_flash();\n\n    const std::uint32_t* source = reinterpret_cast< const std::uint32_t* >( page );\n          std::uint32_t* target = reinterpret_cast< std::uint32_t* >( addr );\n\n    for ( std::size_t count = flash_page_size / sizeof( std::uint32_t* ); count; --count )\n    {\n        *target = *source;\n\n        ++source;\n        ++target;\n        wait_flash();\n    }\n\n    NRF_NVMC->CONFIG = ( NRF_NVMC->CONFIG & ~NVMC_CONFIG_WEN_Msk );\n}\n\nvoid flash_handler::ll_connection_event_happend()\n{\n    if ( num_flash_entries_ && ( NRF_NVMC->READY & NVMC_READY_READY_Ready ) != 0 )\n    {\n        const auto& entry = flash_entries_[ next_flash_entry_ ];\n        erase_flash( entry.address );\n        flash_page( entry.address, entry.values );\n\n        --num_flash_entries_;\n        next_flash_entry_ = ( next_flash_entry_ + 1 ) % number_of_concurrent_flashs;\n\n        bb::end_flash( gatt_server );\n    }\n}\n\ntemplate < typename ConnectionData >\nvoid flash_handler::ll_connection_established(\n         const bluetoe::link_layer::connection_details&   details,\n         const bluetoe::link_layer::connection_addresses&,\n         const ConnectionData& )\n{\n    current_connection_interval_        = details.interval();\n    connection_interval_update_running_ = false;\n}\n\ntemplate < typename ConnectionData >\nvoid flash_handler::ll_connection_changed(\n         const bluetoe::link_layer::connection_details&  details,\n         const ConnectionData& )\n{\n    current_connection_interval_        = details.interval();\n    connection_interval_update_running_ = false;\n}\n\ntemplate < typename ConnectionData >\nvoid flash_handler::ll_connection_closed( std::uint8_t, const ConnectionData& )\n{\n}\n"
  },
  {
    "path": "examples/cc2650/cc26x0f128.lds",
    "content": "/*\r\n @file       cc26x0f128.lds\r\n @brief      CC26x0F128 linker configuration file for GNU compiler.\r\n\r\n @Revised     $Date: 2015-07-21 13:39:51 +0200 (ti, 21 jul 2015) $\r\n @Revision    $Revision: 15951 $\r\n\r\n  Copyright (C) 2014 Texas Instruments Incorporated - http:www.ti.com/\r\n\r\n\r\n  Redistribution and use in source and binary forms, with or without\r\n  modification, are permitted provided that the following conditions\r\n  are met:\r\n\r\n    Redistributions of source code must retain the above copyright\r\n    notice, this list of conditions and the following disclaimer.\r\n\r\n    Redistributions in binary form must reproduce the above copyright\r\n    notice, this list of conditions and the following disclaimer in the\r\n    documentation and/or other materials provided with the distribution.\r\n\r\n    Neither the name of Texas Instruments Incorporated nor the names of\r\n    its contributors may be used to endorse or promote products derived\r\n    from this software without specific prior written permission.\r\n\r\n  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\r\n  \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\r\n  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\r\n  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\r\n  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\r\n  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\r\n  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\r\n  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\r\n  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r\n  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\r\n  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r\n*/\r\n\r\n/*. Entry Point *./\r\nENTRY( ResetIsr )\r\n\r\n/* System memory map */\r\nMEMORY\r\n{\r\n    /* Application stored in and executes from internal flash */\r\n    /* Flash Size 128 KB */\r\n    FLASH (RX) : ORIGIN = 0x0, LENGTH = 0x0001FFA8\r\n    /* Customer Configuration Area (CCFG) */\r\n    FLASH_CCFG (RX) : ORIGIN = 0x1FFA8, LENGTH = 88\r\n    /* Application uses internal RAM for data */\r\n    SRAM (RWX) : ORIGIN = 0x20000000, LENGTH = 0x5000\r\n    /* Application can use GPRAM region as RAM if cache is disabled in the CCFG\r\n       (DEFAULT_CCFG_SIZE_AND_DIS_FLAGS.SET_CCFG_SIZE_AND_DIS_FLAGS_DIS_GPRAM = 0) */\r\n    GPRAM (RWX) : ORIGIN = 0x11000000, LENGTH = 0x2000\r\n}\r\n\r\n/*. Highest address of the stack. Used in startup file .*/\r\n_estack = ORIGIN(SRAM) + LENGTH(SRAM); /*end of SRAM .*/\r\n\r\n/*. Generate a link error if heap and stack don’t fit into RAM .*/\r\n_Min_Heap_Size = 0;\r\n_Min_Stack_Size = 0x100;\r\n\r\n\r\n/* Section allocation in memory */\r\nSECTIONS\r\n{\r\n    .text :\r\n    {\r\n        _text = .;\r\n        KEEP(*(.vectors))\r\n        *(.text*)\r\n        *(.rodata*)\r\n        _etext = .;\r\n    } > FLASH= 0\r\n    .data : AT(ADDR(.text) + SIZEOF(.text))\r\n    {\r\n        _data = .;\r\n        *(vtable)\r\n        *(.data*)\r\n        _edata = .;\r\n    } > SRAM\r\n    .bss :\r\n    {\r\n        _bss = .;\r\n        *(.bss*)\r\n        *(COMMON)\r\n        _ebss = .;\r\n    } > SRAM\r\n    .ccfg :\r\n    { \r\n    } > FLASH_CCFG\r\n    /* User_heap_stack section, used to check that there is enough RAM left */\r\n    ._user_heap_stack :\r\n    {\r\n      . = ALIGN(4);\r\n      . = . + _Min_Heap_Size;\r\n      . = . + _Min_Stack_Size;\r\n      . = ALIGN(4);\r\n    } > SRAM\r\n    .gpram :\r\n    { \r\n    } > GPRAM\r\n}\r\n\r\n"
  },
  {
    "path": "examples/cc2650/ccfg.c",
    "content": "/******************************************************************************\r\n*  Filename:       ccfg.c\r\n*  Revised:        $Date: 2015-07-01 09:11:10 +0200 (on, 01 jul 2015) $\r\n*  Revision:       $Revision: 15909 $\r\n*\r\n*  Description:    Customer Configuration for CC26xx device family (HW rev 2).\r\n*\r\n*  Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/\r\n*\r\n*\r\n*  Redistribution and use in source and binary forms, with or without\r\n*  modification, are permitted provided that the following conditions\r\n*  are met:\r\n*\r\n*    Redistributions of source code must retain the above copyright\r\n*    notice, this list of conditions and the following disclaimer.\r\n*\r\n*    Redistributions in binary form must reproduce the above copyright\r\n*    notice, this list of conditions and the following disclaimer in the\r\n*    documentation and/or other materials provided with the distribution.\r\n*\r\n*    Neither the name of Texas Instruments Incorporated nor the names of\r\n*    its contributors may be used to endorse or promote products derived\r\n*    from this software without specific prior written permission.\r\n*\r\n*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\r\n*  \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\r\n*  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\r\n*  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\r\n*  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\r\n*  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\r\n*  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\r\n*  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\r\n*  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r\n*  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\r\n*  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r\n*\r\n******************************************************************************/\r\n\r\n#include <stdint.h>\r\n#include <inc/hw_types.h>\r\n#include <inc/hw_ccfg.h>\r\n#include <inc/hw_ccfg_simple_struct.h>\r\n\r\n//*****************************************************************************\r\n//\r\n// Introduction\r\n//\r\n// This file contains fields used by Boot ROM, startup code, and SW radio \r\n// stacks to configure chip behavior.\r\n//\r\n// Fields are documented in more details in hw_ccfg.h and CCFG.html in \r\n// DriverLib documentation (doc_overview.html -> CPU Domain Memory Map -> CCFG).\r\n//\r\n//*****************************************************************************\r\n\r\n//*****************************************************************************\r\n//\r\n// Set the values of the individual bit fields.\r\n//\r\n//*****************************************************************************\r\n\r\n//#####################################\r\n// Alternate DC/DC settings\r\n//#####################################\r\n\r\n#define SET_CCFG_SIZE_AND_DIS_FLAGS_DIS_ALT_DCDC_SETTING    0x0    // Alternate DC/DC setting enabled\r\n// #define SET_CCFG_SIZE_AND_DIS_FLAGS_DIS_ALT_DCDC_SETTING 0x1    // Alternate DC/DC setting disabled\r\n\r\n#define SET_CCFG_MODE_CONF_1_ALT_DCDC_VMIN              0x8        // 2.25V\r\n\r\n#define SET_CCFG_MODE_CONF_1_ALT_DCDC_DITHER_EN         0x0        // Disable\r\n// #define SET_CCFG_MODE_CONF_1_ALT_DCDC_DITHER_EN      0x1        // Enable\r\n\r\n#define SET_CCFG_MODE_CONF_1_ALT_DCDC_IPEAK             0x2        // 39mA\r\n\r\n//#####################################\r\n// XOSC override settings\r\n//#####################################\r\n\r\n// #define SET_CCFG_SIZE_AND_DIS_FLAGS_DIS_XOSC_OVR     0x0        // Enable override\r\n#define SET_CCFG_SIZE_AND_DIS_FLAGS_DIS_XOSC_OVR        0x1        // Disable override\r\n\r\n#define SET_CCFG_MODE_CONF_1_DELTA_IBIAS_INIT           0x0        // Delta = 0\r\n\r\n#define SET_CCFG_MODE_CONF_1_DELTA_IBIAS_OFFSET         0x0        // Delta = 0\r\n\r\n#define SET_CCFG_MODE_CONF_1_XOSC_MAX_START             0x10       // 1600us\r\n\r\n//#####################################\r\n// Power settings\r\n//#####################################\r\n\r\n#define SET_CCFG_MODE_CONF_VDDR_TRIM_SLEEP_DELTA        0xF        // Signed delta value to apply to the VDDR_TRIM_SLEEP target, minus one\r\n\r\n#define SET_CCFG_MODE_CONF_DCDC_RECHARGE                0x0        // Use the DC/DC during recharge in powerdown\r\n// #define SET_CCFG_MODE_CONF_DCDC_RECHARGE             0x1        // Do not use the DC/DC during recharge in powerdown\r\n\r\n#define SET_CCFG_MODE_CONF_DCDC_ACTIVE                  0x0        // Use the DC/DC during active mode\r\n// #define SET_CCFG_MODE_CONF_DCDC_ACTIVE               0x1        // Do not use the DC/DC during active mode\r\n\r\n// #define SET_CCFG_MODE_CONF_VDDS_BOD_LEVEL            0x0        // VDDS BOD level is 2.0V\r\n#define SET_CCFG_MODE_CONF_VDDS_BOD_LEVEL               0x1        // VDDS BOD level is 1.8V (or 1.65V for external regulator mode)\r\n\r\n#define SET_CCFG_MODE_CONF_VDDR_CAP                     0x3A       // Unsigned 8-bit integer representing the min. decoupling capacitance on VDDR in units of 100nF\r\n\r\n//#####################################\r\n// Clock settings\r\n//#####################################\r\n\r\n// #define SET_CCFG_MODE_CONF_SCLK_LF_OPTION            0x0        // LF clock derived from High Frequency XOSC\r\n// #define SET_CCFG_MODE_CONF_SCLK_LF_OPTION            0x1        // External LF clock\r\n#define SET_CCFG_MODE_CONF_SCLK_LF_OPTION               0x2        // LF XOSC\r\n// #define SET_CCFG_MODE_CONF_SCLK_LF_OPTION            0x3        // LF RCOSC\r\n\r\n// #define SET_CCFG_MODE_CONF_XOSC_CAP_MOD              0x0        // Apply cap-array delta\r\n#define SET_CCFG_MODE_CONF_XOSC_CAP_MOD                 0x1        // Don't apply cap-array delta \r\n\r\n#define SET_CCFG_MODE_CONF_XOSC_CAPARRAY_DELTA          0xFF       // Signed 8-bit value, directly modifying trimmed XOSC cap-array value\r\n\r\n#define SET_CCFG_EXT_LF_CLK_DIO                         0x01       // DIO number if using external LF clock\r\n\r\n#define SET_CCFG_EXT_LF_CLK_RTC_INCREMENT               0x800000   // RTC increment representing the external LF clock frequency\r\n\r\n//#####################################\r\n// Special HF clock source setting\r\n//#####################################\r\n// #define SET_CCFG_MODE_CONF_XOSC_FREQ                 0x1        // Use BAW oscillator as HF source (if executed on a BAW chip, otherwise uing default (=3))\r\n// #define SET_CCFG_MODE_CONF_XOSC_FREQ                 0x2        // HF source is a 48 MHz xtal\r\n#define SET_CCFG_MODE_CONF_XOSC_FREQ                    0x3        // HF source is a 24 MHz xtal (default)\r\n\r\n//#####################################\r\n// Bootloader settings\r\n//#####################################\r\n\r\n// #define SET_CCFG_BL_CONFIG_BOOTLOADER_ENABLE         0x00       // Disable ROM boot loader\r\n#define SET_CCFG_BL_CONFIG_BOOTLOADER_ENABLE            0xC5       // Enable ROM boot loader\r\n\r\n// #define SET_CCFG_BL_CONFIG_BL_LEVEL                  0x0        // Active low to open boot loader backdoor\r\n#define SET_CCFG_BL_CONFIG_BL_LEVEL                     0x1        // Active high to open boot loader backdoor\r\n\r\n#define SET_CCFG_BL_CONFIG_BL_PIN_NUMBER                0xFF       // DIO number for boot loader backdoor\r\n\r\n// #define SET_CCFG_BL_CONFIG_BL_ENABLE                 0xC5       // Enabled boot loader backdoor\r\n#define SET_CCFG_BL_CONFIG_BL_ENABLE                    0xFF       // Disabled boot loader backdoor\r\n\r\n//#####################################\r\n// Debug access settings\r\n//#####################################\r\n\r\n// #define SET_CCFG_CCFG_TI_OPTIONS_TI_FA_ENABLE        0x00       // Disable unlocking of TI FA option.\r\n#define SET_CCFG_CCFG_TI_OPTIONS_TI_FA_ENABLE           0xC5       // Enable unlocking of TI FA option with the unlock code\r\n\r\n// #define SET_CCFG_CCFG_TAP_DAP_0_CPU_DAP_ENABLE       0x00       // Access disabled\r\n#define SET_CCFG_CCFG_TAP_DAP_0_CPU_DAP_ENABLE          0xC5       // Access enabled if also enabled in FCFG\r\n\r\n// #define SET_CCFG_CCFG_TAP_DAP_0_PRCM_TAP_ENABLE      0x00       // Access disabled\r\n#define SET_CCFG_CCFG_TAP_DAP_0_PRCM_TAP_ENABLE         0xC5       // Access enabled if also enabled in FCFG\r\n\r\n// #define SET_CCFG_CCFG_TAP_DAP_0_TEST_TAP_ENABLE      0x00       // Access disabled\r\n#define SET_CCFG_CCFG_TAP_DAP_0_TEST_TAP_ENABLE         0xC5       // Access enabled if also enabled in FCFG\r\n\r\n// #define SET_CCFG_CCFG_TAP_DAP_1_PBIST2_TAP_ENABLE    0x00       // Access disabled\r\n#define SET_CCFG_CCFG_TAP_DAP_1_PBIST2_TAP_ENABLE       0xC5       // Access enabled if also enabled in FCFG\r\n\r\n// #define SET_CCFG_CCFG_TAP_DAP_1_PBIST1_TAP_ENABLE    0x00       // Access disabled\r\n#define SET_CCFG_CCFG_TAP_DAP_1_PBIST1_TAP_ENABLE       0xC5       // Access enabled if also enabled in FCFG\r\n\r\n// #define SET_CCFG_CCFG_TAP_DAP_1_WUC_TAP_ENABLE       0x00       // Access disabled\r\n#define SET_CCFG_CCFG_TAP_DAP_1_WUC_TAP_ENABLE          0xC5       // Access enabled if also enabled in FCFG\r\n\r\n//#####################################\r\n// Alternative IEEE 802.15.4 MAC address\r\n//#####################################\r\n#define SET_CCFG_IEEE_MAC_0                             0xFFFFFFFF // Bits [31:0]\r\n#define SET_CCFG_IEEE_MAC_1                             0xFFFFFFFF // Bits [63:32]\r\n\r\n//#####################################\r\n// Alternative BLE address\r\n//#####################################\r\n#define SET_CCFG_IEEE_BLE_0                             0xFFFFFFFF // Bits [31:0]\r\n#define SET_CCFG_IEEE_BLE_1                             0xFFFFFFFF // Bits [63:32]\r\n\r\n//#####################################\r\n// Flash erase settings\r\n//#####################################\r\n\r\n// #define SET_CCFG_ERASE_CONF_CHIP_ERASE_DIS_N         0x0        // Any chip erase request detected during boot will be ignored\r\n#define SET_CCFG_ERASE_CONF_CHIP_ERASE_DIS_N            0x1        // Any chip erase request detected during boot will be performed by the boot FW\r\n\r\n// #define SET_CCFG_ERASE_CONF_BANK_ERASE_DIS_N         0x0        // Disable the boot loader bank erase function\r\n#define SET_CCFG_ERASE_CONF_BANK_ERASE_DIS_N            0x1        // Enable the boot loader bank erase function\r\n\r\n//#####################################\r\n// Flash image valid\r\n//#####################################\r\n#define SET_CCFG_IMAGE_VALID_CONF_IMAGE_VALID           0x00000000 // Flash image is valid\r\n// #define SET_CCFG_IMAGE_VALID_CONF_IMAGE_VALID        <non-zero> // Flash image is invalid, call bootloader\r\n\r\n//#####################################\r\n// Flash sector write protection\r\n//#####################################\r\n#define SET_CCFG_CCFG_PROT_31_0                         0xFFFFFFFF\r\n#define SET_CCFG_CCFG_PROT_63_32                        0xFFFFFFFF\r\n#define SET_CCFG_CCFG_PROT_95_64                        0xFFFFFFFF\r\n#define SET_CCFG_CCFG_PROT_127_96                       0xFFFFFFFF\r\n\r\n//#####################################\r\n// Select between cache or GPRAM\r\n//#####################################\r\n// #define SET_CCFG_SIZE_AND_DIS_FLAGS_DIS_GPRAM        0x0        // Cache is disabled and GPRAM is available at 0x11000000-0x11001FFF\r\n#define SET_CCFG_SIZE_AND_DIS_FLAGS_DIS_GPRAM           0x1        // Cache is enabled and GPRAM is disabled (unavailable)\r\n\r\n//*****************************************************************************\r\n//\r\n// CCFG values that should not be modified.\r\n//\r\n//*****************************************************************************\r\n#define SET_CCFG_SIZE_AND_DIS_FLAGS_SIZE_OF_CCFG        0x0058\r\n#define SET_CCFG_SIZE_AND_DIS_FLAGS_DISABLE_FLAGS       0x3FFF\r\n\r\n#define SET_CCFG_MODE_CONF_VDDR_EXT_LOAD                0x1\r\n#define SET_CCFG_MODE_CONF_RTC_COMP                     0x1\r\n#define SET_CCFG_MODE_CONF_HF_COMP                      0x1\r\n\r\n#define SET_CCFG_VOLT_LOAD_0_VDDR_EXT_TP45              0xFF\r\n#define SET_CCFG_VOLT_LOAD_0_VDDR_EXT_TP25              0xFF\r\n#define SET_CCFG_VOLT_LOAD_0_VDDR_EXT_TP5               0xFF\r\n#define SET_CCFG_VOLT_LOAD_0_VDDR_EXT_TM15              0xFF\r\n\r\n#define SET_CCFG_VOLT_LOAD_1_VDDR_EXT_TP125             0xFF\r\n#define SET_CCFG_VOLT_LOAD_1_VDDR_EXT_TP105             0xFF\r\n#define SET_CCFG_VOLT_LOAD_1_VDDR_EXT_TP85              0xFF\r\n#define SET_CCFG_VOLT_LOAD_1_VDDR_EXT_TP65              0xFF\r\n\r\n#define SET_CCFG_RTC_OFFSET_RTC_COMP_P0                 0xFFFF\r\n#define SET_CCFG_RTC_OFFSET_RTC_COMP_P1                 0xFF\r\n#define SET_CCFG_RTC_OFFSET_RTC_COMP_P2                 0xFF\r\n\r\n#define SET_CCFG_FREQ_OFFSET_HF_COMP_P0                 0xFFFF\r\n#define SET_CCFG_FREQ_OFFSET_HF_COMP_P1                 0xFF\r\n#define SET_CCFG_FREQ_OFFSET_HF_COMP_P2                 0xFF\r\n\r\n//*****************************************************************************\r\n//\r\n// Concatenate bit fields to words.\r\n// DO NOT EDIT!\r\n//\r\n//*****************************************************************************\r\n#define DEFAULT_CCFG_O_EXT_LF_CLK        ( \\\r\n\t ( ((uint32_t)( SET_CCFG_EXT_LF_CLK_DIO           << CCFG_EXT_LF_CLK_DIO_S           )) | ~CCFG_EXT_LF_CLK_DIO_M           ) & \\\r\n\t ( ((uint32_t)( SET_CCFG_EXT_LF_CLK_RTC_INCREMENT << CCFG_EXT_LF_CLK_RTC_INCREMENT_S )) | ~CCFG_EXT_LF_CLK_RTC_INCREMENT_M ) )\r\n     \r\n#define DEFAULT_CCFG_MODE_CONF_1         ( \\\r\n\t ( ((uint32_t)( SET_CCFG_MODE_CONF_1_ALT_DCDC_VMIN      << CCFG_MODE_CONF_1_ALT_DCDC_VMIN_S      )) | ~CCFG_MODE_CONF_1_ALT_DCDC_VMIN_M      ) & \\\r\n\t ( ((uint32_t)( SET_CCFG_MODE_CONF_1_ALT_DCDC_DITHER_EN << CCFG_MODE_CONF_1_ALT_DCDC_DITHER_EN_S )) | ~CCFG_MODE_CONF_1_ALT_DCDC_DITHER_EN_M ) & \\\r\n\t ( ((uint32_t)( SET_CCFG_MODE_CONF_1_ALT_DCDC_IPEAK     << CCFG_MODE_CONF_1_ALT_DCDC_IPEAK_S     )) | ~CCFG_MODE_CONF_1_ALT_DCDC_IPEAK_M     ) & \\\r\n\t ( ((uint32_t)( SET_CCFG_MODE_CONF_1_DELTA_IBIAS_INIT   << CCFG_MODE_CONF_1_DELTA_IBIAS_INIT_S   )) | ~CCFG_MODE_CONF_1_DELTA_IBIAS_INIT_M   ) & \\\r\n\t ( ((uint32_t)( SET_CCFG_MODE_CONF_1_DELTA_IBIAS_OFFSET << CCFG_MODE_CONF_1_DELTA_IBIAS_OFFSET_S )) | ~CCFG_MODE_CONF_1_DELTA_IBIAS_OFFSET_M ) & \\\r\n\t ( ((uint32_t)( SET_CCFG_MODE_CONF_1_XOSC_MAX_START     << CCFG_MODE_CONF_1_XOSC_MAX_START_S     )) | ~CCFG_MODE_CONF_1_XOSC_MAX_START_M     ) )\r\n\r\n#define DEFAULT_CCFG_SIZE_AND_DIS_FLAGS  ( \\\r\n\t ( ((uint32_t)( SET_CCFG_SIZE_AND_DIS_FLAGS_SIZE_OF_CCFG         << CCFG_SIZE_AND_DIS_FLAGS_SIZE_OF_CCFG_S         )) | ~CCFG_SIZE_AND_DIS_FLAGS_SIZE_OF_CCFG_M         ) & \\\r\n\t ( ((uint32_t)( SET_CCFG_SIZE_AND_DIS_FLAGS_DISABLE_FLAGS        << CCFG_SIZE_AND_DIS_FLAGS_DISABLE_FLAGS_S        )) | ~CCFG_SIZE_AND_DIS_FLAGS_DISABLE_FLAGS_M        ) & \\\r\n\t ( ((uint32_t)( SET_CCFG_SIZE_AND_DIS_FLAGS_DIS_GPRAM            << CCFG_SIZE_AND_DIS_FLAGS_DIS_GPRAM_S            )) | ~CCFG_SIZE_AND_DIS_FLAGS_DIS_GPRAM_M            ) & \\\r\n\t ( ((uint32_t)( SET_CCFG_SIZE_AND_DIS_FLAGS_DIS_ALT_DCDC_SETTING << CCFG_SIZE_AND_DIS_FLAGS_DIS_ALT_DCDC_SETTING_S )) | ~CCFG_SIZE_AND_DIS_FLAGS_DIS_ALT_DCDC_SETTING_M ) & \\\r\n\t ( ((uint32_t)( SET_CCFG_SIZE_AND_DIS_FLAGS_DIS_XOSC_OVR         << CCFG_SIZE_AND_DIS_FLAGS_DIS_XOSC_OVR_S         )) | ~CCFG_SIZE_AND_DIS_FLAGS_DIS_XOSC_OVR_M         ) )\r\n\r\n#define DEFAULT_CCFG_MODE_CONF           ( \\\r\n\t ( ((uint32_t)( SET_CCFG_MODE_CONF_VDDR_TRIM_SLEEP_DELTA << CCFG_MODE_CONF_VDDR_TRIM_SLEEP_DELTA_S )) | ~CCFG_MODE_CONF_VDDR_TRIM_SLEEP_DELTA_M ) & \\\r\n\t ( ((uint32_t)( SET_CCFG_MODE_CONF_DCDC_RECHARGE         << CCFG_MODE_CONF_DCDC_RECHARGE_S         )) | ~CCFG_MODE_CONF_DCDC_RECHARGE_M         ) & \\\r\n\t ( ((uint32_t)( SET_CCFG_MODE_CONF_DCDC_ACTIVE           << CCFG_MODE_CONF_DCDC_ACTIVE_S           )) | ~CCFG_MODE_CONF_DCDC_ACTIVE_M           ) & \\\r\n\t ( ((uint32_t)( SET_CCFG_MODE_CONF_VDDR_EXT_LOAD         << CCFG_MODE_CONF_VDDR_EXT_LOAD_S         )) | ~CCFG_MODE_CONF_VDDR_EXT_LOAD_M         ) & \\\r\n\t ( ((uint32_t)( SET_CCFG_MODE_CONF_VDDS_BOD_LEVEL        << CCFG_MODE_CONF_VDDS_BOD_LEVEL_S        )) | ~CCFG_MODE_CONF_VDDS_BOD_LEVEL_M        ) & \\\r\n\t ( ((uint32_t)( SET_CCFG_MODE_CONF_SCLK_LF_OPTION        << CCFG_MODE_CONF_SCLK_LF_OPTION_S        )) | ~CCFG_MODE_CONF_SCLK_LF_OPTION_M        ) & \\\r\n\t ( ((uint32_t)( SET_CCFG_MODE_CONF_RTC_COMP              << CCFG_MODE_CONF_RTC_COMP_S              )) | ~CCFG_MODE_CONF_RTC_COMP_M              ) & \\\r\n\t ( ((uint32_t)( SET_CCFG_MODE_CONF_XOSC_FREQ             << CCFG_MODE_CONF_XOSC_FREQ_S             )) | ~CCFG_MODE_CONF_XOSC_FREQ_M             ) & \\\r\n\t ( ((uint32_t)( SET_CCFG_MODE_CONF_XOSC_CAP_MOD          << CCFG_MODE_CONF_XOSC_CAP_MOD_S          )) | ~CCFG_MODE_CONF_XOSC_CAP_MOD_M          ) & \\\r\n\t ( ((uint32_t)( SET_CCFG_MODE_CONF_HF_COMP               << CCFG_MODE_CONF_HF_COMP_S               )) | ~CCFG_MODE_CONF_HF_COMP_M               ) & \\\r\n\t ( ((uint32_t)( SET_CCFG_MODE_CONF_XOSC_CAPARRAY_DELTA   << CCFG_MODE_CONF_XOSC_CAPARRAY_DELTA_S   )) | ~CCFG_MODE_CONF_XOSC_CAPARRAY_DELTA_M   ) & \\\r\n\t ( ((uint32_t)( SET_CCFG_MODE_CONF_VDDR_CAP              << CCFG_MODE_CONF_VDDR_CAP_S              )) | ~CCFG_MODE_CONF_VDDR_CAP_M              ) )\r\n\r\n#define DEFAULT_CCFG_VOLT_LOAD_0         ( \\\r\n\t ( ((uint32_t)( SET_CCFG_VOLT_LOAD_0_VDDR_EXT_TP45 << CCFG_VOLT_LOAD_0_VDDR_EXT_TP45_S )) | ~CCFG_VOLT_LOAD_0_VDDR_EXT_TP45_M ) & \\\r\n\t ( ((uint32_t)( SET_CCFG_VOLT_LOAD_0_VDDR_EXT_TP25 << CCFG_VOLT_LOAD_0_VDDR_EXT_TP25_S )) | ~CCFG_VOLT_LOAD_0_VDDR_EXT_TP25_M ) & \\\r\n\t ( ((uint32_t)( SET_CCFG_VOLT_LOAD_0_VDDR_EXT_TP5  << CCFG_VOLT_LOAD_0_VDDR_EXT_TP5_S  )) | ~CCFG_VOLT_LOAD_0_VDDR_EXT_TP5_M  ) & \\\r\n\t ( ((uint32_t)( SET_CCFG_VOLT_LOAD_0_VDDR_EXT_TM15 << CCFG_VOLT_LOAD_0_VDDR_EXT_TM15_S )) | ~CCFG_VOLT_LOAD_0_VDDR_EXT_TM15_M ) )\r\n\r\n#define DEFAULT_CCFG_VOLT_LOAD_1         ( \\\r\n\t ( ((uint32_t)( SET_CCFG_VOLT_LOAD_1_VDDR_EXT_TP125 << CCFG_VOLT_LOAD_1_VDDR_EXT_TP125_S )) | ~CCFG_VOLT_LOAD_1_VDDR_EXT_TP125_M ) & \\\r\n\t ( ((uint32_t)( SET_CCFG_VOLT_LOAD_1_VDDR_EXT_TP105 << CCFG_VOLT_LOAD_1_VDDR_EXT_TP105_S )) | ~CCFG_VOLT_LOAD_1_VDDR_EXT_TP105_M ) & \\\r\n\t ( ((uint32_t)( SET_CCFG_VOLT_LOAD_1_VDDR_EXT_TP85  << CCFG_VOLT_LOAD_1_VDDR_EXT_TP85_S  )) | ~CCFG_VOLT_LOAD_1_VDDR_EXT_TP85_M  ) & \\\r\n\t ( ((uint32_t)( SET_CCFG_VOLT_LOAD_1_VDDR_EXT_TP65  << CCFG_VOLT_LOAD_1_VDDR_EXT_TP65_S  )) | ~CCFG_VOLT_LOAD_1_VDDR_EXT_TP65_M  ) )\r\n\r\n#define DEFAULT_CCFG_RTC_OFFSET          ( \\\r\n\t ( ((uint32_t)( SET_CCFG_RTC_OFFSET_RTC_COMP_P0 << CCFG_RTC_OFFSET_RTC_COMP_P0_S )) | ~CCFG_RTC_OFFSET_RTC_COMP_P0_M ) & \\\r\n\t ( ((uint32_t)( SET_CCFG_RTC_OFFSET_RTC_COMP_P1 << CCFG_RTC_OFFSET_RTC_COMP_P1_S )) | ~CCFG_RTC_OFFSET_RTC_COMP_P1_M ) & \\\r\n\t ( ((uint32_t)( SET_CCFG_RTC_OFFSET_RTC_COMP_P2 << CCFG_RTC_OFFSET_RTC_COMP_P2_S )) | ~CCFG_RTC_OFFSET_RTC_COMP_P2_M ) )\r\n\r\n#define DEFAULT_CCFG_FREQ_OFFSET         ( \\\r\n\t ( ((uint32_t)( SET_CCFG_FREQ_OFFSET_HF_COMP_P0 << CCFG_FREQ_OFFSET_HF_COMP_P0_S )) | ~CCFG_FREQ_OFFSET_HF_COMP_P0_M ) & \\\r\n\t ( ((uint32_t)( SET_CCFG_FREQ_OFFSET_HF_COMP_P1 << CCFG_FREQ_OFFSET_HF_COMP_P1_S )) | ~CCFG_FREQ_OFFSET_HF_COMP_P1_M ) & \\\r\n\t ( ((uint32_t)( SET_CCFG_FREQ_OFFSET_HF_COMP_P2 << CCFG_FREQ_OFFSET_HF_COMP_P2_S )) | ~CCFG_FREQ_OFFSET_HF_COMP_P2_M ) )\r\n\r\n#define DEFAULT_CCFG_IEEE_MAC_0          SET_CCFG_IEEE_MAC_0\r\n#define DEFAULT_CCFG_IEEE_MAC_1          SET_CCFG_IEEE_MAC_1\r\n#define DEFAULT_CCFG_IEEE_BLE_0          SET_CCFG_IEEE_BLE_0\r\n#define DEFAULT_CCFG_IEEE_BLE_1          SET_CCFG_IEEE_BLE_1\r\n\r\n#define DEFAULT_CCFG_BL_CONFIG           ( \\\r\n\t ( ((uint32_t)( SET_CCFG_BL_CONFIG_BOOTLOADER_ENABLE << CCFG_BL_CONFIG_BOOTLOADER_ENABLE_S )) | ~CCFG_BL_CONFIG_BOOTLOADER_ENABLE_M ) & \\\r\n\t ( ((uint32_t)( SET_CCFG_BL_CONFIG_BL_LEVEL          << CCFG_BL_CONFIG_BL_LEVEL_S          )) | ~CCFG_BL_CONFIG_BL_LEVEL_M          ) & \\\r\n\t ( ((uint32_t)( SET_CCFG_BL_CONFIG_BL_PIN_NUMBER     << CCFG_BL_CONFIG_BL_PIN_NUMBER_S     )) | ~CCFG_BL_CONFIG_BL_PIN_NUMBER_M     ) & \\\r\n\t ( ((uint32_t)( SET_CCFG_BL_CONFIG_BL_ENABLE         << CCFG_BL_CONFIG_BL_ENABLE_S         )) | ~CCFG_BL_CONFIG_BL_ENABLE_M         ) )\r\n\r\n#define DEFAULT_CCFG_ERASE_CONF          ( \\\r\n\t ( ((uint32_t)( SET_CCFG_ERASE_CONF_CHIP_ERASE_DIS_N << CCFG_ERASE_CONF_CHIP_ERASE_DIS_N_S )) | ~CCFG_ERASE_CONF_CHIP_ERASE_DIS_N_M ) & \\\r\n\t ( ((uint32_t)( SET_CCFG_ERASE_CONF_BANK_ERASE_DIS_N << CCFG_ERASE_CONF_BANK_ERASE_DIS_N_S )) | ~CCFG_ERASE_CONF_BANK_ERASE_DIS_N_M ) )\r\n\r\n#define DEFAULT_CCFG_CCFG_TI_OPTIONS     ( \\\r\n\t ( ((uint32_t)( SET_CCFG_CCFG_TI_OPTIONS_TI_FA_ENABLE << CCFG_CCFG_TI_OPTIONS_TI_FA_ENABLE_S )) | ~CCFG_CCFG_TI_OPTIONS_TI_FA_ENABLE_M ) )\r\n\r\n#define DEFAULT_CCFG_CCFG_TAP_DAP_0      ( \\\r\n\t ( ((uint32_t)( SET_CCFG_CCFG_TAP_DAP_0_CPU_DAP_ENABLE  << CCFG_CCFG_TAP_DAP_0_CPU_DAP_ENABLE_S  )) | ~CCFG_CCFG_TAP_DAP_0_CPU_DAP_ENABLE_M  ) & \\\r\n\t ( ((uint32_t)( SET_CCFG_CCFG_TAP_DAP_0_PRCM_TAP_ENABLE << CCFG_CCFG_TAP_DAP_0_PRCM_TAP_ENABLE_S )) | ~CCFG_CCFG_TAP_DAP_0_PRCM_TAP_ENABLE_M ) & \\\r\n\t ( ((uint32_t)( SET_CCFG_CCFG_TAP_DAP_0_TEST_TAP_ENABLE << CCFG_CCFG_TAP_DAP_0_TEST_TAP_ENABLE_S )) | ~CCFG_CCFG_TAP_DAP_0_TEST_TAP_ENABLE_M ) )\r\n\r\n#define DEFAULT_CCFG_CCFG_TAP_DAP_1      ( \\\r\n\t ( ((uint32_t)( SET_CCFG_CCFG_TAP_DAP_1_PBIST2_TAP_ENABLE << CCFG_CCFG_TAP_DAP_1_PBIST2_TAP_ENABLE_S )) | ~CCFG_CCFG_TAP_DAP_1_PBIST2_TAP_ENABLE_M ) & \\\r\n\t ( ((uint32_t)( SET_CCFG_CCFG_TAP_DAP_1_PBIST1_TAP_ENABLE << CCFG_CCFG_TAP_DAP_1_PBIST1_TAP_ENABLE_S )) | ~CCFG_CCFG_TAP_DAP_1_PBIST1_TAP_ENABLE_M ) & \\\r\n\t ( ((uint32_t)( SET_CCFG_CCFG_TAP_DAP_1_WUC_TAP_ENABLE    << CCFG_CCFG_TAP_DAP_1_WUC_TAP_ENABLE_S    )) | ~CCFG_CCFG_TAP_DAP_1_WUC_TAP_ENABLE_M    ) )\r\n\r\n#define DEFAULT_CCFG_IMAGE_VALID_CONF    ( \\\r\n\t ( ((uint32_t)( SET_CCFG_IMAGE_VALID_CONF_IMAGE_VALID << CCFG_IMAGE_VALID_CONF_IMAGE_VALID_S )) | ~CCFG_IMAGE_VALID_CONF_IMAGE_VALID_M ) )\r\n\r\n#define DEFAULT_CCFG_CCFG_PROT_31_0      SET_CCFG_CCFG_PROT_31_0  \r\n#define DEFAULT_CCFG_CCFG_PROT_63_32     SET_CCFG_CCFG_PROT_63_32 \r\n#define DEFAULT_CCFG_CCFG_PROT_95_64     SET_CCFG_CCFG_PROT_95_64 \r\n#define DEFAULT_CCFG_CCFG_PROT_127_96    SET_CCFG_CCFG_PROT_127_96\r\n\r\n//*****************************************************************************\r\n//\r\n// Customer Configuration Area in Lock Page\r\n//\r\n//*****************************************************************************\r\n#if defined(__IAR_SYSTEMS_ICC__)\r\n__root const ccfg_t __ccfg @ \".ccfg\" =\r\n#elif defined(__TI_COMPILER_VERSION__)\r\n#pragma DATA_SECTION(__ccfg, \".ccfg\")\r\n#pragma RETAIN(__ccfg)\r\nconst ccfg_t __ccfg =\r\n#else\r\nconst ccfg_t __ccfg __attribute__((section(\".ccfg\"))) __attribute__((used)) =\r\n#endif\r\n{                                     // Mapped to address\r\n    DEFAULT_CCFG_O_EXT_LF_CLK       , // 0x50003FA8 (0x50003xxx maps to last\r\n    DEFAULT_CCFG_MODE_CONF_1        , // 0x50003FAC  sector in FLASH.\r\n    DEFAULT_CCFG_SIZE_AND_DIS_FLAGS , // 0x50003FB0  Independent of FLASH size)\r\n    DEFAULT_CCFG_MODE_CONF          , // 0x50003FB4\r\n    DEFAULT_CCFG_VOLT_LOAD_0        , // 0x50003FB8 \r\n    DEFAULT_CCFG_VOLT_LOAD_1        , // 0x50003FBC\r\n    DEFAULT_CCFG_RTC_OFFSET         , // 0x50003FC0\r\n    DEFAULT_CCFG_FREQ_OFFSET        , // 0x50003FC4\r\n    DEFAULT_CCFG_IEEE_MAC_0         , // 0x50003FC8\r\n    DEFAULT_CCFG_IEEE_MAC_1         , // 0x50003FCC\r\n    DEFAULT_CCFG_IEEE_BLE_0         , // 0x50003FD0\r\n    DEFAULT_CCFG_IEEE_BLE_1         , // 0x50003FD4\r\n    DEFAULT_CCFG_BL_CONFIG          , // 0x50003FD8\r\n    DEFAULT_CCFG_ERASE_CONF         , // 0x50003FDC\r\n    DEFAULT_CCFG_CCFG_TI_OPTIONS    , // 0x50003FE0\r\n    DEFAULT_CCFG_CCFG_TAP_DAP_0     , // 0x50003FE4\r\n    DEFAULT_CCFG_CCFG_TAP_DAP_1     , // 0x50003FE8\r\n    DEFAULT_CCFG_IMAGE_VALID_CONF   , // 0x50003FEC\r\n    DEFAULT_CCFG_CCFG_PROT_31_0     , // 0x50003FF0\r\n    DEFAULT_CCFG_CCFG_PROT_63_32    , // 0x50003FF4\r\n    DEFAULT_CCFG_CCFG_PROT_95_64    , // 0x50003FF8\r\n    DEFAULT_CCFG_CCFG_PROT_127_96   , // 0x50003FFC\r\n};\r\n"
  },
  {
    "path": "examples/cc2650/startup_gcc.c",
    "content": "/******************************************************************************\r\n*  Filename:       startup_gcc.c\r\n*  Revised:        $Date: 2015-05-19 15:09:27 +0200 (ti, 19 mai 2015) $\r\n*  Revision:       $Revision: 15737 $\r\n*\r\n*  Description:    Startup code for CC26xx PG2 device family for use with GCC.\r\n*\r\n*  Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/\r\n*\r\n*\r\n*  Redistribution and use in source and binary forms, with or without\r\n*  modification, are permitted provided that the following conditions\r\n*  are met:\r\n*\r\n*    Redistributions of source code must retain the above copyright\r\n*    notice, this list of conditions and the following disclaimer.\r\n*\r\n*    Redistributions in binary form must reproduce the above copyright\r\n*    notice, this list of conditions and the following disclaimer in the\r\n*    documentation and/or other materials provided with the distribution.\r\n*\r\n*    Neither the name of Texas Instruments Incorporated nor the names of\r\n*    its contributors may be used to endorse or promote products derived\r\n*    from this software without specific prior written permission.\r\n*\r\n*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\r\n*  \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\r\n*  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\r\n*  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\r\n*  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\r\n*  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\r\n*  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\r\n*  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\r\n*  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r\n*  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\r\n*  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r\n*\r\n******************************************************************************/\r\n\r\n//*****************************************************************************\r\n//\r\n// Check if compiler is GNU Compiler\r\n//\r\n//*****************************************************************************\r\n#if !(defined(__GNUC__))\r\n#error \"startup_gcc.c: Unsupported compiler!\"\r\n#endif\r\n\r\n#include <inc/hw_types.h>\r\n\r\n\r\n//*****************************************************************************\r\n//\r\n// Macro for weak symbol aliasing\r\n//\r\n//*****************************************************************************\r\n#define WEAK_ALIAS(x) __attribute__ ((weak, alias(#x)))\r\n\r\n//*****************************************************************************\r\n//\r\n// Forward declaration of the reset ISR and the default fault handlers.\r\n//\r\n//*****************************************************************************\r\nvoid        ResetISR( void );\r\nstatic void NmiSRHandler( void );\r\nstatic void FaultISRHandler( void );\r\nstatic void IntDefaultHandler( void );\r\nextern int  main( void );\r\n\r\n\r\n// Default interrupt handlers\r\nvoid NmiSR(void) WEAK_ALIAS(NmiSRHandler);\r\nvoid FaultISR(void) WEAK_ALIAS(FaultISRHandler);\r\nvoid MPUFaultIntHandler(void) WEAK_ALIAS(IntDefaultHandler);\r\nvoid BusFaultIntHandler(void) WEAK_ALIAS(IntDefaultHandler);\r\nvoid UsageFaultIntHandler(void) WEAK_ALIAS(IntDefaultHandler);\r\nvoid SVCallIntHandler(void) WEAK_ALIAS(IntDefaultHandler);\r\nvoid DebugMonIntHandler(void) WEAK_ALIAS(IntDefaultHandler);\r\nvoid PendSVIntHandler(void) WEAK_ALIAS(IntDefaultHandler);\r\nvoid SysTickIntHandler(void) WEAK_ALIAS(IntDefaultHandler);\r\nvoid GPIOIntHandler(void) WEAK_ALIAS(IntDefaultHandler);\r\nvoid I2CIntHandler(void) WEAK_ALIAS(IntDefaultHandler);\r\nvoid RFCCPE1IntHandler(void) WEAK_ALIAS(IntDefaultHandler);\r\nvoid AONIntHandler(void) WEAK_ALIAS(IntDefaultHandler);\r\nvoid AONRTCIntHandler(void) WEAK_ALIAS(IntDefaultHandler);\r\nvoid UART0IntHandler(void) WEAK_ALIAS(IntDefaultHandler);\r\nvoid AUXSWEvent0IntHandler(void) WEAK_ALIAS(IntDefaultHandler);\r\nvoid SSI0IntHandler(void) WEAK_ALIAS(IntDefaultHandler);\r\nvoid SSI1IntHandler(void) WEAK_ALIAS(IntDefaultHandler);\r\nvoid RFCCPE0IntHandler(void) WEAK_ALIAS(IntDefaultHandler);\r\nvoid RFCHardwareIntHandler(void) WEAK_ALIAS(IntDefaultHandler);\r\nvoid RFCCmdAckIntHandler(void) WEAK_ALIAS(IntDefaultHandler);\r\nvoid I2SIntHandler(void) WEAK_ALIAS(IntDefaultHandler);\r\nvoid AUXSWEvent1IntHandler(void) WEAK_ALIAS(IntDefaultHandler);\r\nvoid WatchdogIntHandler(void) WEAK_ALIAS(IntDefaultHandler);\r\nvoid Timer0AIntHandler(void) WEAK_ALIAS(IntDefaultHandler);\r\nvoid Timer0BIntHandler(void) WEAK_ALIAS(IntDefaultHandler);\r\nvoid Timer1AIntHandler(void) WEAK_ALIAS(IntDefaultHandler);\r\nvoid Timer1BIntHandler(void) WEAK_ALIAS(IntDefaultHandler);\r\nvoid Timer2AIntHandler(void) WEAK_ALIAS(IntDefaultHandler);\r\nvoid Timer2BIntHandler(void) WEAK_ALIAS(IntDefaultHandler);\r\nvoid Timer3AIntHandler(void) WEAK_ALIAS(IntDefaultHandler);\r\nvoid Timer3BIntHandler(void) WEAK_ALIAS(IntDefaultHandler);\r\nvoid CryptoIntHandler(void) WEAK_ALIAS(IntDefaultHandler);\r\nvoid uDMAIntHandler(void) WEAK_ALIAS(IntDefaultHandler);\r\nvoid uDMAErrIntHandler(void) WEAK_ALIAS(IntDefaultHandler);\r\nvoid FlashIntHandler(void) WEAK_ALIAS(IntDefaultHandler);\r\nvoid SWEvent0IntHandler(void) WEAK_ALIAS(IntDefaultHandler);\r\nvoid AUXCombEventIntHandler(void) WEAK_ALIAS(IntDefaultHandler);\r\nvoid AONProgIntHandler(void) WEAK_ALIAS(IntDefaultHandler);\r\nvoid DynProgIntHandler(void) WEAK_ALIAS(IntDefaultHandler);\r\nvoid AUXCompAIntHandler(void) WEAK_ALIAS(IntDefaultHandler);\r\nvoid AUXADCIntHandler(void) WEAK_ALIAS(IntDefaultHandler);\r\nvoid TRNGIntHandler(void) WEAK_ALIAS(IntDefaultHandler);\r\n\r\n//*****************************************************************************\r\n//\r\n//! The entry point for the device trim fxn.\r\n//\r\n//*****************************************************************************\r\nextern void trimDevice(void);\r\n\r\n//*****************************************************************************\r\n//\r\n// The following are constructs created by the linker, indicating where the\r\n// the \"data\" and \"bss\" segments reside in memory.  The initializers for the\r\n// for the \"data\" segment resides immediately following the \"text\" segment.\r\n//\r\n//*****************************************************************************\r\nextern uint32_t _etext;\r\nextern uint32_t _data;\r\nextern uint32_t _edata;\r\nextern uint32_t _bss;\r\nextern uint32_t _ebss;\r\nextern uint32_t _estack;\r\n\r\n//*****************************************************************************\r\n//\r\n//! The vector table. Note that the proper constructs must be placed on this to\r\n//! ensure that it ends up at physical address 0x0000.0000 or at the start of\r\n//! the program if located at a start address other than 0.\r\n//\r\n//*****************************************************************************\r\n__attribute__ ((section(\".vectors\"), used))\r\nvoid (* const gVectors[])(void) =\r\n{\r\n    (void (*)(void))&_estack,               // The initial stack pointer\r\n    ResetISR,                               // The reset handler\r\n    NmiSR,                                  // The NMI handler\r\n    FaultISR,                               // The hard fault handler\r\n    MPUFaultIntHandler,                     // The MPU fault handler\r\n    BusFaultIntHandler,                     // The bus fault handler\r\n    UsageFaultIntHandler,                   // The usage fault handler\r\n    0,                                      // Reserved\r\n    0,                                      // Reserved\r\n    0,                                      // Reserved\r\n    0,                                      // Reserved\r\n    SVCallIntHandler,                       // SVCall handler\r\n    DebugMonIntHandler,                     // Debug monitor handler\r\n    0,                                      // Reserved\r\n    PendSVIntHandler,                       // The PendSV handler\r\n    SysTickIntHandler,                      // The SysTick handler\r\n    GPIOIntHandler,                         // AON edge detect\r\n    I2CIntHandler,                          // I2C\r\n    RFCCPE1IntHandler,                      // RF Core Command & Packet Engine 1\r\n    AONIntHandler,                          // AON SpiSplave Rx, Tx and CS\r\n    AONRTCIntHandler,                       // AON RTC\r\n    UART0IntHandler,                        // UART0 Rx and Tx\r\n    AUXSWEvent0IntHandler,                  // AUX software event 0\r\n    SSI0IntHandler,                         // SSI0 Rx and Tx\r\n    SSI1IntHandler,                         // SSI1 Rx and Tx\r\n    RFCCPE0IntHandler,                      // RF Core Command & Packet Engine 0\r\n    RFCHardwareIntHandler,                  // RF Core Hardware\r\n    RFCCmdAckIntHandler,                    // RF Core Command Acknowledge\r\n    I2SIntHandler,                          // I2S\r\n    AUXSWEvent1IntHandler,                  // AUX software event 1\r\n    WatchdogIntHandler,                     // Watchdog timer\r\n    Timer0AIntHandler,                      // Timer 0 subtimer A\r\n    Timer0BIntHandler,                      // Timer 0 subtimer B\r\n    Timer1AIntHandler,                      // Timer 1 subtimer A\r\n    Timer1BIntHandler,                      // Timer 1 subtimer B\r\n    Timer2AIntHandler,                      // Timer 2 subtimer A\r\n    Timer2BIntHandler,                      // Timer 2 subtimer B\r\n    Timer3AIntHandler,                      // Timer 3 subtimer A\r\n    Timer3BIntHandler,                      // Timer 3 subtimer B\r\n    CryptoIntHandler,                       // Crypto Core Result available\r\n    uDMAIntHandler,                         // uDMA Software\r\n    uDMAErrIntHandler,                      // uDMA Error\r\n    FlashIntHandler,                        // Flash controller\r\n    SWEvent0IntHandler,                     // Software Event 0\r\n    AUXCombEventIntHandler,                 // AUX combined event\r\n    AONProgIntHandler,                      // AON programmable 0\r\n    DynProgIntHandler,                      // Dynamic Programmable interrupt\r\n                                            // source (Default: PRCM)\r\n    AUXCompAIntHandler,                     // AUX Comparator A\r\n    AUXADCIntHandler,                       // AUX ADC new sample or ADC DMA\r\n                                            // done, ADC underflow, ADC overflow\r\n    TRNGIntHandler                          // TRNG event\r\n};\r\n\r\n\r\n//*****************************************************************************\r\n//\r\n//! This is the code that gets called when the processor first starts execution\r\n//! following a reset event. Only the absolutely necessary set is performed,\r\n//! after which the application supplied entry() routine is called. Any fancy\r\n//! actions (such as making decisions based on the reset cause register, and\r\n//! resetting the bits in that register) are left solely in the hands of the\r\n//! application.\r\n//\r\n//*****************************************************************************\r\nvoid\r\nResetISR(void)\r\n{\r\n\tuint32_t *pui32Src, *pui32Dest;\r\n\r\n    //\r\n    // Final trim of device\r\n    //\r\n    trimDevice();\r\n\r\n    //\r\n    // Copy the data segment initializers from flash to SRAM.\r\n    //\r\n    pui32Src = &_etext;\r\n    for(pui32Dest = &_data; pui32Dest < &_edata; )\r\n    {\r\n        *pui32Dest++ = *pui32Src++;\r\n    }\r\n\r\n    //\r\n    // Zero fill the bss segment.\r\n    //\r\n    __asm(\"    ldr     r0, =_bss\\n\"\r\n          \"    ldr     r1, =_ebss\\n\"\r\n          \"    mov     r2, #0\\n\"\r\n          \"    .thumb_func\\n\"\r\n          \"zero_loop:\\n\"\r\n          \"        cmp     r0, r1\\n\"\r\n          \"        it      lt\\n\"\r\n          \"        strlt   r2, [r0], #4\\n\"\r\n          \"        blt     zero_loop\");\r\n\r\n   //\r\n   // Call the application's entry point.\r\n   //\r\n   main();\r\n\r\n    //\r\n    // If we ever return signal Error\r\n    //\r\n    FaultISR();\r\n}\r\n\r\n//*****************************************************************************\r\n//\r\n//! This is the code that gets called when the processor receives a NMI. This\r\n//! simply enters an infinite loop, preserving the system state for examination\r\n//! by a debugger.\r\n//\r\n//*****************************************************************************\r\nstatic void\r\nNmiSRHandler(void)\r\n{\r\n    //\r\n    // Enter an infinite loop.\r\n    //\r\n    while(1)\r\n    {\r\n    }\r\n}\r\n\r\n//*****************************************************************************\r\n//\r\n//! This is the code that gets called when the processor receives a fault\r\n//! interrupt. This simply enters an infinite loop, preserving the system state\r\n//! for examination by a debugger.\r\n//\r\n//*****************************************************************************\r\nstatic void\r\nFaultISRHandler(void)\r\n{\r\n    //\r\n    // Enter an infinite loop.\r\n    //\r\n    while(1)\r\n    {\r\n    }\r\n}\r\n\r\n//*****************************************************************************\r\n//\r\n//! This is the code that gets called when the processor receives an unexpected\r\n//! interrupt. This simply enters an infinite loop, preserving the system state\r\n//! for examination by a debugger.\r\n//\r\n//*****************************************************************************\r\nstatic void\r\nIntDefaultHandler(void)\r\n{\r\n    //\r\n    // Go into an infinite loop.\r\n    //\r\n    while(1)\r\n    {\r\n    }\r\n}\r\n"
  },
  {
    "path": "examples/cmake/deduce.cmake",
    "content": "set(board_controller_mapping\n    PCA10056 NRF52840\n    PCA10040 NRF52832)\n\n# Map given in the form \"key1 value1 key2 value2...\"\nfunction(map_lookup result_var map key)\n    list(FIND ${map} ${key} index)\n    math(EXPR next_index \"${index} | 1\")\n\n    if ( index EQUAL -1 OR next_index EQUAL index )\n        set(${result_var}-NOTFOUND NOTFOUND PARENT_SCOPE)\n    else()\n        list(GET ${map} ${next_index} output)\n        set(${result_var} ${output} PARENT_SCOPE)\n    endif()\nendfunction()\n\nfunction(deduce_binding result_var board)\n    map_lookup(result board_controller_mapping ${board})\n\n    if (DEFINED result-NOTFOUND)\n        message(FATAL_ERROR \"Unknow board: ${board}\")\n    endif()\n    set(${result_var} ${result} PARENT_SCOPE)\nendfunction()\n\nfunction(deduce_bluetoe_binding result_var controller)\n    set(${result_var} nrf52 PARENT_SCOPE)\nendfunction()\n\nfunction(set_preprocessore_macros)\nendfunction()"
  },
  {
    "path": "examples/cmake/gcc-arm-none-eabi.cmake",
    "content": "set(CMAKE_SYSTEM_NAME       Generic)\nset(CMAKE_SYSTEM_PROCESSOR  arm)\n\nset(CMAKE_TRY_COMPILE_PLATFORM_VARIABLES ARM_GCC_TOOL_PATH)\n\nif (NOT DEFINED ARM_GCC_TOOL_PATH OR NOT EXISTS ${ARM_GCC_TOOL_PATH}/bin)\n    find_program(\n        ARM_NONE_EABI_GCC_PATH\n        arm-none-eabi-gcc\n        REQUIRED)\n\n    if (DEFINED ARM_NONE_EABI_GCC_PATH-NOTFOUND)\n        message(FATAL_ERROR\n                \"To configure the arm-none-eabi-gcc correctly, \"\n                \"please set ARM_GCC_TOOL_PATH to the path that \"\n                \"contains the bin directory of your GCC installation.\")\n    endif()\n\n    get_filename_component(ARM_NONE_EABI_GCC_PATH_BASE ${ARM_NONE_EABI_GCC_PATH} DIRECTORY)\n\n    set(tools_path ${ARM_NONE_EABI_GCC_PATH_BASE})\nelse()\n    set(tools_path ${ARM_GCC_TOOL_PATH}/bin)\nendif()\n\nset(tools_prefix ${tools_path}/arm-none-eabi-)\n\nset(CMAKE_C_COMPILER    ${tools_prefix}gcc)\nset(CMAKE_CXX_COMPILER  ${tools_prefix}g++)\nset(CMAKE_SIZE          ${tools_prefix}size)\n\n# for init check\nset(CMAKE_EXE_LINKER_FLAGS_INIT --specs=nosys.specs)\n\nset(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)\nset(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)\nset(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)\nset(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)\n"
  },
  {
    "path": "examples/custom_advertising.cpp",
    "content": "/**\n * @example purpose of this example is, to show how any required advertising data of scan response can\n *          be archived, but circumventing all automatism provided by Bluetoe.\n */\n\n#include <bluetoe/server.hpp>\n#include <bluetoe/custom_advertising.hpp>\n#include <bluetoe/device.hpp>\n\nusing namespace bluetoe;\n\nstatic const std::uint8_t blob[] = {\n    'H', 'a', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd'\n};\n\nstatic const std::uint8_t advertising_data[] = {\n    0x02, 0x01, 0x06,           // «Flags» , LE General Discoverable Mode, BR/EDR Not Supported.\n    0x06, 0xff,                 // «Manufacturer Specific Data»\n    0x69, 0x02,                 // Torrox\n    0x22, 0x23, 0x44,           // Data\n    0x02, 0x0A, 0x00,           // «TX Power Level»\n};\n\nstatic const std::uint8_t scan_response_data[] = {\n    0x03, 0x19, 0xC1, 0x03,     // «Appearance» Keyboard\n};\n\nusing advertising_server = server<\n    custom_advertising_data< sizeof( advertising_data ), advertising_data >,\n    custom_scan_response_data< sizeof( scan_response_data ), scan_response_data >,\n    service<\n        service_uuid< 0x52CBA985, 0x7E3C, 0x4ECD, 0xBDF1, 0x2708157E080B >,\n        characteristic<\n            fixed_blob_value< blob, sizeof( blob ) >\n        >\n    >\n>;\n\ndevice< advertising_server > gatt_srv;\n\nint main()\n{\n    for ( ;; )\n        gatt_srv.run();\n}\n"
  },
  {
    "path": "examples/cycling_speed_and_cadence.cpp",
    "content": "#include <bluetoe/server.hpp>\n#include <bluetoe/device.hpp>\n#include <bluetoe/services/csc.hpp>\n#include <bluetoe/sensor_location.hpp>\n#include <nrf.h>\n\nstruct handler {\n\n    /*\n     * Functions required by the bluetoe CSC implementation to support wheel and crank revolutions\n     */\n    std::pair< std::uint32_t, std::uint16_t > cumulative_wheel_revolutions_and_time()\n    {\n        return std::make_pair( wheel_revolutions_, last_wheel_event_time_ );\n    }\n\n    std::pair< std::uint16_t, std::uint16_t > cumulative_crank_revolutions_and_time()\n    {\n        return std::make_pair( crank_revolutions_, last_crank_event_time_ );\n    }\n\n    void set_cumulative_wheel_revolutions( std::uint32_t new_value );\n\n    volatile std::uint32_t wheel_revolutions_;\n    volatile std::uint16_t last_wheel_event_time_;\n\n    volatile std::uint32_t crank_revolutions_;\n    volatile std::uint16_t last_crank_event_time_;\n};\n\nstatic constexpr char server_name[] = \"Gruener Blitz\";\n\nusing bicycle = bluetoe::server<\n    bluetoe::server_name< server_name >,\n    bluetoe::appearance::cycling_speed_and_cadence_sensor,\n    bluetoe::cycling_speed_and_cadence<\n        bluetoe::sensor_location::hip,\n        bluetoe::csc::wheel_revolution_data_supported,\n        bluetoe::csc::crank_revolution_data_supported,\n        bluetoe::csc::handler< handler >\n    >\n>;\n\nbluetoe::device< bicycle > server;\n\nvoid handler::set_cumulative_wheel_revolutions( std::uint32_t new_value )\n{\n    wheel_revolutions_ = new_value;\n    server.confirm_cumulative_wheel_revolutions( server );\n}\n\nvoid init_bike_hardware();\n\nint main()\n{\n    init_bike_hardware();\n\n    for ( ;; )\n        server.run( );\n}\n\nstatic constexpr int wheel_pin_nr       = 16;\nstatic constexpr int wheel_channel_nr   = 0;\nstatic constexpr int cadence_pin_nr     = 17;\nstatic constexpr int cadence_channel_nr = 1;\nstatic constexpr int timer_devider      = 100;\n\n// for easier debugging\nstatic NRF_GPIOTE_Type* const nrf_gpiote = NRF_GPIOTE;\nstatic NRF_GPIO_Type* const   nrf_gpio   = NRF_GPIO;\nstatic NRF_TIMER_Type* const  nrf_timer  = NRF_TIMER2;\n\nstatic volatile std::uint16_t now       = 0;\nstatic volatile std::uint16_t last_now  = 0;\n\nextern \"C\" void TIMER2_IRQHandler()\n{\n    nrf_timer->EVENTS_COMPARE[ 0 ] = 0;\n    now += timer_devider;\n}\n\nextern \"C\" void GPIOTE_IRQHandler()\n{\n    if ( nrf_gpiote->EVENTS_IN[ wheel_channel_nr ] )\n    {\n        ++server.wheel_revolutions_;\n        server.last_wheel_event_time_ = now;\n        nrf_gpiote->EVENTS_IN[ wheel_channel_nr ] = 0;\n    }\n\n    if ( nrf_gpiote->EVENTS_IN[ cadence_channel_nr ] )\n    {\n        ++server.crank_revolutions_;\n        server.last_crank_event_time_ = now;\n        nrf_gpiote->EVENTS_IN[ cadence_channel_nr ] = 0;\n    }\n\n    server.notify_timed_update( server );\n}\n\nvoid init_bike_hardware()\n{\n    nrf_gpio->PIN_CNF[ wheel_pin_nr ] =\n        (GPIO_PIN_CNF_PULL_Pullup << GPIO_PIN_CNF_PULL_Pos);\n\n    nrf_gpio->PIN_CNF[ cadence_pin_nr ] =\n        (GPIO_PIN_CNF_PULL_Pullup << GPIO_PIN_CNF_PULL_Pos);\n\n    // Enable interrupts on rising age on pin\n    nrf_gpiote->CONFIG[ wheel_channel_nr ] =\n        (GPIOTE_CONFIG_POLARITY_LoToHi << GPIOTE_CONFIG_POLARITY_Pos)\n    |   (GPIOTE_CONFIG_MODE_Event << GPIOTE_CONFIG_MODE_Pos)\n    |   (wheel_pin_nr << GPIOTE_CONFIG_PSEL_Pos);\n\n    nrf_gpiote->CONFIG[ cadence_channel_nr ] =\n        (GPIOTE_CONFIG_POLARITY_LoToHi << GPIOTE_CONFIG_POLARITY_Pos)\n    |   (GPIOTE_CONFIG_MODE_Event << GPIOTE_CONFIG_MODE_Pos)\n    |   (cadence_pin_nr << GPIOTE_CONFIG_PSEL_Pos);\n\n    nrf_gpiote->INTENSET =\n        (GPIOTE_INTENSET_IN0_Enabled << GPIOTE_INTENSET_IN0_Pos)\n    |   (GPIOTE_INTENSET_IN1_Enabled << GPIOTE_INTENSET_IN1_Pos);\n\n    nrf_gpiote->EVENTS_IN[ wheel_channel_nr ] = 0;\n    nrf_gpiote->EVENTS_IN[ cadence_channel_nr ] = 0;\n\n    NVIC_SetPriority( GPIOTE_IRQn, 3 );\n    NVIC_ClearPendingIRQ( GPIOTE_IRQn );\n    NVIC_EnableIRQ( GPIOTE_IRQn );\n\n    nrf_timer->INTENCLR = 0xffff;\n    nrf_timer->MODE     =\n        (TIMER_MODE_MODE_Timer << TIMER_MODE_MODE_Pos);\n\n    nrf_timer->BITMODE  =\n        (TIMER_BITMODE_BITMODE_16Bit << TIMER_BITMODE_BITMODE_Pos);\n\n    // for 1024hz, we would need a prescale of lb(13.931)\n    // this makes 16Mhz / 2^9 == 31.25khz\n    nrf_timer->PRESCALER = 9;\n\n    // if we want the ISR to be called with 1024hz/100, we would reset the timer at\n    nrf_timer->CC[ 0 ] = 31250 * timer_devider / 1024;\n    nrf_timer->SHORTS  =\n        (TIMER_SHORTS_COMPARE0_CLEAR_Enabled << TIMER_SHORTS_COMPARE0_CLEAR_Pos);\n    nrf_timer->INTENSET =\n        (TIMER_INTENSET_COMPARE0_Enabled << TIMER_INTENSET_COMPARE0_Pos);\n\n    NVIC_SetPriority( TIMER2_IRQn, 2 );\n    NVIC_ClearPendingIRQ( TIMER2_IRQn );\n    NVIC_EnableIRQ( TIMER2_IRQn );\n\n    nrf_timer->TASKS_START = 1;\n}\n"
  },
  {
    "path": "examples/docker/Dockerfile",
    "content": "FROM frolvlad/alpine-glibc as base\n\nRUN  apk update \\\n     && apk add --no-cache --update git tar wget ncurses libusb unzip ninja cmake make \\\n     && rm /lib64/ld-linux-x86-64.so.2 \\\n     && ln -s /usr/glibc-compat/lib/ld-linux-x86-64.so.2 /lib64/ld-linux-x86-64.so.2\n\nRUN mkdir -p /opt/ && cd /opt &&  \\\n    wget -q https://www.nordicsemi.com/-/media/Software-and-other-downloads/SDKs/nRF5/Binaries/nRF5_SDK_17.1.0_ddde560.zip \\\n        && unzip -q nRF5_SDK_17.1.0_ddde560.zip \"nRF5_SDK_17.1.0_ddde560/components/toolchain/cmsis/include/*\" \\\n           \"nRF5_SDK_17.1.0_ddde560/modules/*\" -d . \\\n        && mv nRF5_SDK_17.1.0_ddde560 nrf5_sdk \\\n        && rm nRF5_SDK_17.1.0_ddde560.zip\n\nRUN wget -q https://developer.arm.com/-/media/Files/downloads/gnu-rm/10.3-2021.10/gcc-arm-none-eabi-10.3-2021.10-x86_64-linux.tar.bz2 -P /usr/local \\\n        && tar -C /usr/local -xf /usr/local/gcc-arm-none-eabi-10.3-2021.10-x86_64-linux.tar.bz2 --no-same-owner \\\n        && rm /usr/local/gcc-arm-none-eabi-10.3-2021.10-x86_64-linux.tar.bz2\n"
  },
  {
    "path": "examples/docker/Makefile",
    "content": "# Container engine to be used (typically: podman|docker)\nCONTAINER_ENGINE := docker\n\n# Name of the container image\nCONTAINER_IMAGE ?= bluetoe_alpine\n\n# Mount point where the quark-derived project will exist within the container\nCONTAINER_TARGET := /work\n\nCOMMAND ?= mkdir -p ../build && cd ../build && cmake -GNinja -DARM_GCC_TOOL_PATH=/usr/local/gcc-arm-none-eabi-10.3-2021.10/ -DNRF5_SDK_ROOT=/opt/nrf5_sdk/ -DCMAKE_TOOLCHAIN_FILE=../cmake/gcc-arm-none-eabi.cmake .. && ninja\n\n.PHONY: all\nall: container-build\n\n.PHONY: clean\nclean:\n\trm -rf ../build\n\n.PHONY: container-build-image\ncontainer-build-image:\n\t@image_sha=`$(CONTAINER_ENGINE) images -q $(CONTAINER_IMAGE)`;\\\n\tif [ -z \"$$image_sha\" ];\\\n    then\\\n    echo \"Building $(CONTAINER_IMAGE). This will take a few minutes...\";\\\n\t$(CONTAINER_ENGINE) build --rm --tag $(CONTAINER_IMAGE) .;\\\n\telse\\\n    echo \"Using existing image $(CONTAINER_IMAGE)-> $$image_sha \";\\\n\tfi\n\n# If there is no local image with the required image name, the recipe tries to pull\n# the image from a container registry.\n.PHONY: container-pull-image\ncontainer-pull-image:\n\t@image_sha=`$(CONTAINER_ENGINE) images -q $(CONTAINER_IMAGE)`;\\\n\tif [ -z \"$$image_sha\" ];\\\n    then\\\n    echo \"Did not find a local container image with name:$(CONTAINER_IMAGE). Fetching one from the container registry...\";\\\n\t$(CONTAINER_ENGINE) pull $(CONTAINER_IMAGE);\\\n\telse\\\n    echo \"Using existing local image $(CONTAINER_IMAGE)-> $$image_sha \";\\\n\tfi\n\n.PHONY: container-shell\ncontainer-shell: container-build-image\n\t@$(CONTAINER_ENGINE) run --rm -ti \\\n\t--user=$(shell id -u):$(shell id -g) \\\n\t--mount type=\"bind,src=$(PWD)/../..,target=$(CONTAINER_TARGET)\" \\\n\t--workdir=\"$(CONTAINER_TARGET)\" $(CONTAINER_IMAGE)\n\n.PHONY: container-build\ncontainer-build: container-build-image\n\t$(CONTAINER_ENGINE) run --rm -ti \\\n\t--user=$(shell id -u):$(shell id -g) \\\n\t--mount type=\"bind,src=$(PWD)/../..,target=$(CONTAINER_TARGET)\" \\\n\t--workdir=\"$(CONTAINER_TARGET)/examples/docker\" \\\n\t$(CONTAINER_IMAGE) sh -c \"$(COMMAND)\"\n\n.PHONY: container-delete\ncontainer-delete:\n\t@$(CONTAINER_ENGINE) rmi $(CONTAINER_IMAGE)\n\n.PHONY: help\nhelp:\n\t@echo \"Supported targets:\"\n\t@echo \"  all                     Executes the ./buildAll.sh script inside the container\"\n\t@echo \"  container-build-image   Builds the $(CONTAINER_IMAGE) image based on the Dockerfile\"\n\t@echo \"  container-pull-image    Fetches the $(CONTAINER_IMAGE) image from the container registry\"\n\t@echo \"  container-shell         Opens a shell in a temporary container\"\n\t@echo \"  container-build         Executes COMMAND inside a temporary container\"\n\t@echo \"  container-delete        Deletes the $(CONTAINER_IMAGE) image\"\n\t@echo \"  help                    You're looking at it\"\n"
  },
  {
    "path": "examples/doxygen/CMakeLists.txt",
    "content": "function(add_doxygen_example TARGETNAME)\n    add_library(${TARGETNAME} ${TARGETNAME}.cpp)\n    add_dependencies(build_examples ${TARGETNAME})\nendfunction()\n\nadd_custom_target(build_examples)\n\nadd_doxygen_example(server_example)\nadd_doxygen_example(include_example)\nadd_doxygen_example(read_write_handler_example)\nadd_doxygen_example(change_advertising_example)\nadd_doxygen_example(priorities_example)"
  },
  {
    "path": "examples/doxygen/change_advertising_example.cpp",
    "content": "#include <bluetoe/server.hpp>\n#include <bluetoe/bindings/nrf52.hpp>\n\nstatic std::uint8_t write_handler( bool flag );\n\nusing gatt = bluetoe::server<\n    bluetoe::service<\n        bluetoe::service_uuid< 0xD91F985A, 0x7F39, 0x4BBF, 0x8CA4, 0xCEB3DA28BB5D >,\n        bluetoe::characteristic<\n            bluetoe::free_write_handler< bool, write_handler >\n        >\n    >\n>;\n\nbluetoe::nrf52<\n    gatt,\n    bluetoe::link_layer::connectable_undirected_advertising,\n    bluetoe::link_layer::connectable_directed_advertising\n> link_layer;\n\n\n\nstatic std::uint8_t write_handler( bool flag )\n{\n    // change the advertising type according to the give flag value\n    if ( flag )\n    {\n        link_layer.change_advertising< bluetoe::link_layer::connectable_undirected_advertising >();\n    }\n    else\n    {\n        link_layer.change_advertising< bluetoe::link_layer::connectable_directed_advertising >();\n        link_layer.directed_advertising_address(\n            bluetoe::link_layer::random_device_address( { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 } ) );\n    }\n\n    return bluetoe::error_codes::success;\n}\n"
  },
  {
    "path": "examples/doxygen/include_example.cpp",
    "content": "#include <bluetoe/server.hpp>\n#include <bluetoe/service.hpp>\n#include <bluetoe/characteristic.hpp>\n#include <cstdint>\n\nstd::int32_t temperature;\n\nusing sensor_position_uuid = bluetoe::service_uuid< 0xD9473E00, 0xE7D3, 0x4D90, 0x9366, 0x282AC4F44FEB >;\n\ntypedef bluetoe::server<\n    /*\n     * A server consists of two services, on beeing included to the other\n     */\n    bluetoe::secondary_service<\n        sensor_position_uuid,\n        bluetoe::characteristic<\n            bluetoe::fixed_uint8_value< 0x42 >\n        >\n    >,\n    bluetoe::service<\n        bluetoe::service_uuid< 0x8C8B4094, 0x0DE2, 0x499F, 0xA28A, 0x4EED5BC73CA9 >,\n        bluetoe::include_service< sensor_position_uuid >,\n        bluetoe::characteristic<\n            bluetoe::bind_characteristic_value< decltype( temperature ), &temperature >,\n            bluetoe::no_read_access\n        >\n    >\n> temperature_service;\n"
  },
  {
    "path": "examples/doxygen/priorities_example.cpp",
    "content": "\n#include <bluetoe/server.hpp>\n#include <bluetoe/service.hpp>\n#include <bluetoe/characteristic.hpp>\n#include <bluetoe/outgoing_priority.hpp>\n#include <cstdint>\n\n// the enumeration of the possible axis\nenum class axis {\n    X, Y, Z\n};\n\n// a handler that will use a sensor depending on the axis X\ntemplate < axis X >\nstruct acceleration_measurement_handler\n{\n    /*\n     * This handler function will respond to requests to the acceleration sensors value or,\n     * when the server was requested to send a notification of this characteristic.\n     */\n    std::uint8_t read_sensor_value( std::size_t, std::uint8_t* out_buffer, std::size_t& out_size );\n\n    /*\n     * This handler function will be called to fill the content of a temperatur alarm notification\n     * and is thus more important to reach a GATT client than the characteristic above.\n     */\n    std::uint8_t temperature_alarm( std::size_t, std::uint8_t* out_buffer, std::size_t& out_size );\n};\n\n// the definition of a service that provides access to the value of a given access\ntemplate < class UUID, axis X >\nusing acceleration_measurement_service = bluetoe::service<\n    UUID,\n    bluetoe::mixin< acceleration_measurement_handler< X > >,\n    bluetoe::characteristic<\n        bluetoe::characteristic_uuid< 0xCBD99443, 0x85C2, 0x415B, 0x901B, 0x23C0CAE8B0B8 >,\n        bluetoe::mixin_read_handler<\n            acceleration_measurement_handler< X >,\n            &acceleration_measurement_handler< X >::read_sensor_value >,\n        bluetoe::notify\n    >,\n    bluetoe::characteristic<\n        bluetoe::characteristic_uuid< 0xCBD99443, 0x85C2, 0x415B, 0x901B, 0x23C0CAE8B0B8 >,\n        bluetoe::mixin_read_handler<\n            acceleration_measurement_handler< X >,\n            &acceleration_measurement_handler< X >::temperature_alarm >,\n        bluetoe::notify\n    >,\n    // make sure, that temperature alarms are send out with higher priority\n    bluetoe::higher_outgoing_priority<\n        bluetoe::characteristic_uuid< 0xCBD99443, 0x85C2, 0x415B, 0x901B, 0x23C0CAE8B0B8 >\n    >\n>;\n\n/*\n * A server with 3 similar acceleration services.\n */\nusing helicopter = bluetoe::server<\n    acceleration_measurement_service<\n        bluetoe::service_uuid< 0x8C8B4094, 0x0DE2, 0x499F, 0xA28A, 0x4EED5BC73CA9 >,\n        axis::X\n    >,\n    // this service messures the altitude and is thus more important than the other\n    // axis.\n    bluetoe::higher_outgoing_priority<\n        bluetoe::service_uuid< 0x8C8B4094, 0x0DE2, 0x499F, 0xA28A, 0x4EED5BC73CA9 >\n    >,\n    acceleration_measurement_service<\n        bluetoe::service_uuid< 0x8C8B4095, 0x0DE2, 0x499F, 0xA28A, 0x4EED5BC73CA9 >,\n        axis::Y\n    >,\n    acceleration_measurement_service<\n        bluetoe::service_uuid< 0x8C8B4096, 0x0DE2, 0x499F, 0xA28A, 0x4EED5BC73CA9 >,\n        axis::Z\n    >\n>;\n\nint main()\n{}"
  },
  {
    "path": "examples/doxygen/read_write_handler_example.cpp",
    "content": "#include <bluetoe/server.hpp>\n#include <bluetoe/service.hpp>\n#include <bluetoe/codes.hpp>\n\nstd::uint8_t read_blob_handler( std::size_t offset, std::size_t, std::uint8_t* out_buffer, std::size_t& out_size )\n{\n    if ( offset == 0 )\n    {\n        *out_buffer = 42;\n        out_size    = 1;\n\n        return bluetoe::error_codes::success;\n    }\n\n    return bluetoe::error_codes::invalid_offset;\n}\n\nstd::uint8_t read_handler( std::size_t, std::uint8_t* out_buffer, std::size_t& out_size )\n{\n    *out_buffer = 42;\n    out_size    = 1;\n\n    return bluetoe::error_codes::success;\n}\n\nstd::uint8_t write_blob_handler( std::size_t, std::size_t, const std::uint8_t* )\n{\n    return bluetoe::error_codes::write_not_permitted;\n}\n\nstd::uint8_t write_handler( std::size_t, const std::uint8_t* )\n{\n    return bluetoe::error_codes::write_not_permitted;\n}\n\nstruct static_handler {\n    static constexpr std::uint8_t code_word[] = { 'a', 'b', 'c' };\n\n    static std::uint8_t read( std::size_t offset, std::size_t read_size, std::uint8_t* out_buffer, std::size_t& out_size )\n    {\n        if ( offset > sizeof( code_word ) )\n            return bluetoe::error_codes::invalid_offset;\n\n        out_size = std::min( read_size, sizeof( code_word ) - offset );\n        std::copy( &code_word[ offset ], &code_word[ offset + out_size], out_buffer );\n\n        return bluetoe::error_codes::success;\n    }\n\n    static std::uint8_t write( std::size_t, std::size_t, const std::uint8_t* )\n    {\n        return bluetoe::error_codes::write_not_permitted;\n    }\n};\n\n\nstruct handler {\n    std::uint8_t read_blob( std::size_t, std::size_t, std::uint8_t*, std::size_t& )\n    {\n        return bluetoe::error_codes::success;\n    }\n\n    std::uint8_t write_blob( std::size_t, std::size_t, const std::uint8_t* )\n    {\n        return bluetoe::error_codes::write_not_permitted;\n    }\n\n    std::uint8_t read_blob_c( std::size_t offset, std::size_t read_size, std::uint8_t* out_buffer, std::size_t& out_size ) const;\n    std::uint8_t read_blob_v( std::size_t offset, std::size_t read_size, std::uint8_t* out_buffer, std::size_t& out_size ) volatile;\n    std::uint8_t read_blob_vc( std::size_t offset, std::size_t read_size, std::uint8_t* out_buffer, std::size_t& out_size ) const volatile;\n} handler_instance;\n\nbluetoe::server<\n    bluetoe::service<\n        bluetoe::service_uuid< 0x8C8B4094, 0x0DE2, 0x499F, 0xA28A, 0x4EED5BC73CA9 >,\n        bluetoe::characteristic<\n            bluetoe::free_read_blob_handler< &read_blob_handler >,\n            bluetoe::free_write_blob_handler< &write_blob_handler >\n        >,\n        bluetoe::characteristic<\n            bluetoe::free_read_handler< &read_handler >,\n            bluetoe::free_raw_write_handler< &write_handler >\n        >,\n        bluetoe::characteristic<\n            bluetoe::free_read_blob_handler< &static_handler::read >,\n            bluetoe::free_write_blob_handler< &static_handler::write >\n        >,\n        bluetoe::characteristic<\n            bluetoe::read_blob_handler< handler, handler_instance, &handler::read_blob >,\n            bluetoe::write_blob_handler< handler, handler_instance, &handler::write_blob >\n        >\n    >\n> gatt_server;"
  },
  {
    "path": "examples/doxygen/server_example.cpp",
    "content": "\n#include <bluetoe/server.hpp>\n#include <bluetoe/service.hpp>\n#include <bluetoe/characteristic.hpp>\n#include <cstdint>\n\nstd::int32_t temperature;\n\ntypedef bluetoe::server<\n    /*\n     * A server consists of at least one service\n     */\n    bluetoe::service<\n        bluetoe::service_uuid< 0x8C8B4094, 0x0DE2, 0x499F, 0xA28A, 0x4EED5BC73CA9 >,\n        bluetoe::characteristic<\n            bluetoe::bind_characteristic_value< decltype( temperature ), &temperature >,\n            bluetoe::no_read_access\n        >\n    >\n> temperature_service;\n"
  },
  {
    "path": "examples/gpio.cpp",
    "content": "/**\n * @brief the purpose of this example is to show:\n * - How pairing can be configured\n * - How bonding can be implemented\n */\n\n#include <bluetoe/server.hpp>\n#include <bluetoe/service.hpp>\n#include <bluetoe/characteristic.hpp>\n#include <bluetoe/device.hpp>\n\n#include <nrf.h>\n\n// Button 1 and LED 1 a Nordic PCA10056 eval board\nstatic constexpr std::uint32_t input_pin    = 11u;\nstatic constexpr std::uint32_t output_pin   = 13u;\n\nstatic NRF_TIMER_Type& display_timer    = *NRF_TIMER3;\nstatic NRF_TIMER_Type& debounce_timer   = *NRF_TIMER2;\nstatic NRF_GPIOTE_Type& gpiote          = *NRF_GPIOTE;\nstatic NRF_GPIO_Type&  port0            = *NRF_P0;\n\nstatic constexpr std::uint32_t debounce_timeout = 1000u;\n\nstatic const char server_name[] = \"GPIO-Example\";\nstatic const char input_pin_name[] = \"Button 1\";\nstatic const char output_pin_name[] = \"LED 1\";\n\nstatic void set_output_pin( bool state )\n{\n    ( state\n        ? static_cast< volatile std::uint32_t& >( port0.OUTCLR )\n        : static_cast< volatile std::uint32_t& >( port0.OUTSET ) ) = ( 1 << output_pin );\n}\n\nstatic bool output_pin_state()\n{\n    return ( port0.OUT & ( 1 << output_pin ) ) == 0;\n}\n\nstatic bool input_pin_state()\n{\n    return ( port0.IN & ( 1 << input_pin ) ) == 0;\n}\n\nstatic bool input_pin_value = input_pin_state();\n\nstatic std::uint8_t write_output_pin( bool state )\n{\n    set_output_pin( state );\n\n    return bluetoe::error_codes::success;\n}\n\nusing gatt_server = bluetoe::server<\n    bluetoe::server_name< server_name >,\n    bluetoe::service<\n        bluetoe::requires_encryption,\n        bluetoe::service_uuid< 0xDE346753, 0x5194, 0x4748, 0xADA4, 0xAB483FE1D370 >,\n        bluetoe::characteristic<\n            bluetoe::characteristic_uuid< 0xDE346753, 0x5194, 0x4748, 0xADA4, 0xAB483FE1D370 >,\n            bluetoe::characteristic_name< input_pin_name >,\n            bluetoe::notify,\n            bluetoe::bind_characteristic_value< bool, &input_pin_value >\n        >,\n        bluetoe::characteristic<\n            bluetoe::characteristic_uuid< 0xDE346753, 0x5194, 0x4748, 0xADA4, 0xAB483FE1D371 >,\n            bluetoe::characteristic_name< output_pin_name >,\n            bluetoe::free_write_handler< bool, write_output_pin >\n        >\n    >,\n    bluetoe::max_mtu_size< 65 >\n>;\n\nclass pairing_io_t\n{\npublic:\n    pairing_io_t()\n        : response_( nullptr )\n        , timer_elapsed_( false )\n    {\n    }\n\n    void sm_pairing_numeric_output( int pass_key )\n    {\n        store_pass_key( pass_key );\n        display_digit_ = 0;\n\n        setup_timer();\n        display_first_digit();\n    }\n\n    void sm_pairing_yes_no( bluetoe::pairing_yes_no_response& response )\n    {\n        response_ = &response;\n    }\n\n    void interrupt_handler()\n    {\n        timer_elapsed_ = true;\n    }\n\n    void input_pin_toggled()\n    {\n        input_pin_toggled_ = true;\n    }\n\n    void handle_events();\n\nprivate:\n    void handle_key_press();\n    void handle_display_timer();\n\n    void store_pass_key( int pass_key )\n    {\n        for ( int digit = 0; digit != pass_key_length; ++digit )\n        {\n            auto& num_blinks = pass_key_[ pass_key_length - digit - 1 ];\n\n            num_blinks = static_cast< std::uint8_t >( pass_key % 10 );\n            if ( num_blinks == 0 )\n                num_blinks = 10;\n\n            pass_key /= 10;\n        }\n    }\n\n    void display_first_digit()\n    {\n        --pass_key_[ display_digit_ ];\n        set_output_pin( true );\n\n        display_timer.CC[ 0 ]     = led_on_time;\n        display_timer.TASKS_START = 1;\n    }\n\n    void setup_timer()\n    {\n        timer_elapsed_ = false;\n        display_timer.EVENTS_COMPARE[ 0 ] = 0;\n        display_timer.PRESCALER = ( 15 << TIMER_PRESCALER_PRESCALER_Pos );\n        display_timer.BITMODE   = ( TIMER_BITMODE_BITMODE_32Bit << TIMER_BITMODE_BITMODE_Pos );\n        display_timer.SHORTS    =\n            ( TIMER_SHORTS_COMPARE0_CLEAR_Enabled << TIMER_SHORTS_COMPARE0_CLEAR_Pos )\n          | ( TIMER_SHORTS_COMPARE0_STOP_Enabled << TIMER_SHORTS_COMPARE0_STOP_Pos );\n        display_timer.INTENSET = ( TIMER_INTENSET_COMPARE0_Enabled << TIMER_INTENSET_COMPARE0_Pos );\n\n        NVIC_ClearPendingIRQ( TIMER3_IRQn );\n        NVIC_EnableIRQ( TIMER3_IRQn );\n    }\n\n    void disable_timer()\n    {\n        NVIC_DisableIRQ( TIMER3_IRQn );\n        display_timer.INTENCLR = ( TIMER_INTENCLR_COMPARE0_Clear << TIMER_INTENCLR_COMPARE0_Pos );\n        display_timer.TASKS_STOP = 1;\n    }\n\n    static constexpr int led_on_time     = 4000;\n    static constexpr int led_off_time    = 10000;\n    static constexpr int pause_time      = 3 * ( led_on_time + led_off_time );\n    static constexpr int pass_key_length = 6;\n\n    bluetoe::pairing_yes_no_response* response_;\n    int display_digit_;\n    std::uint8_t pass_key_[ pass_key_length ];\n    volatile bool timer_elapsed_;\n    volatile bool input_pin_toggled_;\n} pairing_io;\n\nbluetoe::device<\n    gatt_server,\n    // Support for legacy and LESC pairing\n    bluetoe::security_manager,\n    // Configure Link Layer to support at least an MTU of 65\n    bluetoe::link_layer::buffer_sizes< 200, 200 >,\n    // This application has some meaning to output a pass key and to input a yes/no\n    bluetoe::pairing_numeric_output< pairing_io_t, pairing_io >,\n    bluetoe::pairing_yes_no< pairing_io_t, pairing_io >\n> server;\n\nstatic void init_hardware()\n{\n    set_output_pin( false );\n    port0.PIN_CNF[ output_pin ] =\n        ( GPIO_PIN_CNF_DRIVE_S0H1 << GPIO_PIN_CNF_DRIVE_Pos ) |\n        ( GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos );\n\n    port0.PIN_CNF[ input_pin ] =\n        ( GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos )\n      | ( GPIO_PIN_CNF_PULL_Pullup << GPIO_PIN_CNF_PULL_Pos );\n\n    gpiote.CONFIG[ 0 ] =\n        ( GPIOTE_CONFIG_MODE_Event << GPIOTE_CONFIG_MODE_Pos )\n      | ( input_pin << GPIOTE_CONFIG_PSEL_Pos )\n      | ( GPIOTE_CONFIG_POLARITY_Toggle << GPIOTE_CONFIG_POLARITY_Pos );\n\n    gpiote.EVENTS_IN[ 0 ] = 0;\n    gpiote.INTENSET = ( GPIOTE_INTENSET_IN0_Set << GPIOTE_INTENSET_IN0_Pos );\n\n    NVIC_ClearPendingIRQ( GPIOTE_IRQn );\n    NVIC_EnableIRQ( GPIOTE_IRQn );\n}\n\nint main()\n{\n    init_hardware();\n\n    for ( ;; )\n    {\n        pairing_io.handle_events();\n        server.run();\n    }\n}\n\nvoid pairing_io_t::handle_events()\n{\n    handle_key_press();\n    handle_display_timer();\n}\n\nvoid pairing_io_t::handle_key_press()\n{\n    if ( !input_pin_toggled_ )\n        return;\n\n    input_pin_toggled_ = false;\n\n    input_pin_value = input_pin_state();\n\n    server.notify( input_pin_value );\n\n    if ( response_ )\n    {\n        response_->yes_no_response( input_pin_value );\n        response_ = nullptr;\n    }\n}\n\nvoid pairing_io_t::handle_display_timer()\n{\n    if ( !timer_elapsed_ )\n        return;\n\n    timer_elapsed_ = false;\n\n    if ( output_pin_state() )\n    {\n        // Switch to OFF\n        set_output_pin( false );\n\n        if ( pass_key_[ display_digit_ ] == 0 )\n        {\n            ++display_digit_;\n\n            if ( display_digit_ == pass_key_length )\n            {\n                disable_timer();\n                return;\n            }\n\n            display_timer.CC[ 0 ] = pause_time;\n        }\n        else\n        {\n            display_timer.CC[ 0 ] = led_off_time;\n        }\n\n        assert( pass_key_[ display_digit_ ] <= 10 );\n        --pass_key_[ display_digit_ ];\n    }\n    else\n    {\n        // Switch to ON\n        set_output_pin( true );\n        display_timer.CC[ 0 ]    = led_on_time;\n    }\n\n    display_timer.TASKS_START = 1;\n}\n\nextern \"C\" void TIMER3_IRQHandler()\n{\n    display_timer.EVENTS_COMPARE[ 0 ] = 0;\n    pairing_io.interrupt_handler();\n}\n\nextern \"C\" void TIMER2_IRQHandler()\n{\n    debounce_timer.INTENCLR            = ( TIMER_INTENCLR_COMPARE0_Enabled << TIMER_INTENCLR_COMPARE0_Pos );\n    debounce_timer.EVENTS_COMPARE[ 0 ] = 0;\n\n    if ( input_pin_value != input_pin_state() )\n    {\n        pairing_io.input_pin_toggled();\n    }\n\n    gpiote.INTENSET = ( GPIOTE_INTENSET_IN0_Set << GPIOTE_INTENSET_IN0_Pos );\n}\n\nextern \"C\" void GPIOTE_IRQHandler()\n{\n    // disable input interrupt, setup timer for debouncing\n    gpiote.INTENCLR       = ( GPIOTE_INTENCLR_IN0_Clear << GPIOTE_INTENCLR_IN0_Pos );\n    gpiote.EVENTS_IN[ 0 ] = 0;\n\n    debounce_timer.EVENTS_COMPARE[ 0 ] = 0;\n    debounce_timer.PRESCALER = ( 15 << TIMER_PRESCALER_PRESCALER_Pos );\n    debounce_timer.BITMODE   = ( TIMER_BITMODE_BITMODE_32Bit << TIMER_BITMODE_BITMODE_Pos );\n    debounce_timer.SHORTS    =\n        ( TIMER_SHORTS_COMPARE0_CLEAR_Enabled << TIMER_SHORTS_COMPARE0_CLEAR_Pos )\n      | ( TIMER_SHORTS_COMPARE0_STOP_Enabled << TIMER_SHORTS_COMPARE0_STOP_Pos );\n    debounce_timer.INTENSET = ( TIMER_INTENSET_COMPARE0_Enabled << TIMER_INTENSET_COMPARE0_Pos );\n\n    NVIC_ClearPendingIRQ( TIMER2_IRQn );\n    NVIC_EnableIRQ( TIMER2_IRQn );\n\n    debounce_timer.CC[ 0 ] = debounce_timeout;\n    debounce_timer.TASKS_START = 1;\n\n    pairing_io.input_pin_toggled();\n}\n"
  },
  {
    "path": "examples/keyboard.cpp",
    "content": "#include <bluetoe/server.hpp>\n#include <bluetoe/device.hpp>\n#include <bluetoe/services/bas.hpp>\n#include <bluetoe/services/dis.hpp>\n#include <bluetoe/services/hid.hpp>\n#include <bluetoe/descriptor.hpp>\n\n#include <nrf.h>\n\nstatic constexpr std::uint32_t suspend_mode_led_pin = 17;\n\nvoid set_led( std::uint32_t pin, bool on )\n{\n    NRF_GPIO->OUT = on\n        ? NRF_GPIO->OUT & ~( 1 << pin )\n        : NRF_GPIO->OUT | ( 1 << pin );\n}\n\nvoid init_hardware()\n{\n    NRF_GPIO->PIN_CNF[ suspend_mode_led_pin ] =\n        ( GPIO_PIN_CNF_DRIVE_S0H1 << GPIO_PIN_CNF_DRIVE_Pos ) |\n        ( GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos );\n\n}\n\n // shamless stolen from the Nordic examples\nstatic const std::uint8_t report_map_data[] =\n{\n    0x05, 0x01,       // Usage Page (Generic Desktop)\n    0x09, 0x06,       // Usage (Keyboard)\n    0xA1, 0x01,       // Collection (Application)\n    0x05, 0x07,       // Usage Page (Key Codes)\n    0x19, 0xe0,       // Usage Minimum (224)\n    0x29, 0xe7,       // Usage Maximum (231)\n    0x15, 0x00,       // Logical Minimum (0)\n    0x25, 0x01,       // Logical Maximum (1)\n    0x75, 0x01,       // Report Size (1)\n    0x95, 0x08,       // Report Count (8)\n    0x81, 0x02,       // Input (Data, Variable, Absolute)\n\n    0x95, 0x01,       // Report Count (1)\n    0x75, 0x08,       // Report Size (8)\n    0x81, 0x01,       // Input (Constant) reserved byte(1)\n\n    0x95, 0x05,       // Report Count (5)\n    0x75, 0x01,       // Report Size (1)\n    0x05, 0x08,       // Usage Page (Page# for LEDs)\n    0x19, 0x01,       // Usage Minimum (1)\n    0x29, 0x05,       // Usage Maximum (5)\n    0x91, 0x02,       // Output (Data, Variable, Absolute), Led report\n    0x95, 0x01,       // Report Count (1)\n    0x75, 0x03,       // Report Size (3)\n    0x91, 0x01,       // Output (Data, Variable, Absolute), Led report padding\n\n    0x95, 0x06,       // Report Count (6)\n    0x75, 0x08,       // Report Size (8)\n    0x15, 0x00,       // Logical Minimum (0)\n    0x25, 0x65,       // Logical Maximum (101)\n    0x05, 0x07,       // Usage Page (Key codes)\n    0x19, 0x00,       // Usage Minimum (0)\n    0x29, 0x65,       // Usage Maximum (101)\n    0x81, 0x00,       // Input (Data, Array) Key array(6 bytes)\n\n    0x09, 0x05,       // Usage (Vendor Defined)\n    0x15, 0x00,       // Logical Minimum (0)\n    0x26, 0xFF, 0x00, // Logical Maximum (255)\n    0x75, 0x08,       // Report Count (2)\n    0x95, 0x02,       // Report Size (8 bit)\n    0xB1, 0x02,       // Feature (Data, Variable, Absolute)\n\n    0xC0              // End Collection (Application)\n};\n\nstatic const std::uint8_t hid_information[] =\n{\n    0x11, 0x01,         // USB HID Version 1.11\n    0x00,               // Hardware target country.\n    0x02,               // RemoteWake = false; NormallyConnectable = true\n};\n\nclass keyboard_handler\n{\npublic:\n    keyboard_handler()\n        : mode_( protocol_mode::report )\n    {\n        set_led( suspend_mode_led_pin, false );\n    }\n\n    int read_battery_level()\n    {\n        return 99;\n    }\n\n    std::uint8_t protocol_mode_write_handler( std::size_t write_size, const std::uint8_t* value )\n    {\n        if ( write_size == 1 && ( *value == protocol_mode::boot || *value == protocol_mode::report ) )\n        {\n            mode_ = static_cast< decltype( mode_ ) >( *value );\n        }\n\n        return bluetoe::error_codes::success;\n    }\n\n    std::uint8_t protocol_mode_read_handler( std::size_t, std::uint8_t* out_buffer, std::size_t& out_size )\n    {\n        *out_buffer = mode_;\n        out_size = 1;\n\n        return bluetoe::error_codes::success;\n    }\n\n    std::uint8_t input_report_write_handler( std::size_t write_size, const std::uint8_t* value )\n    {\n        (void)write_size;\n        (void)value;\n        return bluetoe::error_codes::success;\n    }\n\n    std::uint8_t input_report_read_handler( std::size_t read_size, std::uint8_t* out_buffer, std::size_t& out_size )\n    {\n        (void)read_size;\n        (void)out_buffer;\n        (void)out_size;\n        return bluetoe::error_codes::success;\n    }\n\n    std::uint8_t output_report_write_handler( std::size_t write_size, const std::uint8_t* value )\n    {\n        (void)write_size;\n        (void)value;\n        return bluetoe::error_codes::success;\n    }\n\n    std::uint8_t output_report_read_handler( std::size_t read_size, std::uint8_t* out_buffer, std::size_t& out_size )\n    {\n        (void)read_size;\n        (void)out_buffer;\n        (void)out_size;\n        return bluetoe::error_codes::success;\n    }\n\n    std::uint8_t feature_report_write_handler( std::size_t write_size, const std::uint8_t* value )\n    {\n        (void)write_size;\n        (void)value;\n        return bluetoe::error_codes::success;\n    }\n\n    std::uint8_t feature_report_read_handler( std::size_t read_size, std::uint8_t* out_buffer, std::size_t& out_size )\n    {\n        (void)read_size;\n        (void)out_buffer;\n        (void)out_size;\n        return bluetoe::error_codes::success;\n    }\n\n    std::uint8_t boot_input_write_handler( std::size_t write_size, const std::uint8_t* value )\n    {\n        (void)write_size;\n        (void)value;\n        return bluetoe::error_codes::success;\n    }\n\n    std::uint8_t boot_input_read_handler( std::size_t read_size, std::uint8_t* out_buffer, std::size_t& out_size )\n    {\n        (void)read_size;\n        (void)out_buffer;\n        (void)out_size;\n        return bluetoe::error_codes::success;\n    }\n\n    std::uint8_t boot_output_write_handler( std::size_t write_size, const std::uint8_t* value )\n    {\n        (void)write_size;\n        (void)value;\n        return bluetoe::error_codes::success;\n    }\n\n    std::uint8_t boot_output_read_handler( std::size_t read_size, std::uint8_t* out_buffer, std::size_t& out_size )\n    {\n        (void)read_size;\n        (void)out_buffer;\n        (void)out_size;\n        return bluetoe::error_codes::success;\n    }\n\n    std::uint8_t control_point_write_handler( std::size_t write_size, const std::uint8_t* value )\n    {\n        if ( write_size == 1 && ( *value == opcodes::suspend || *value == opcodes::exit_suspend ) )\n        {\n            set_led( suspend_mode_led_pin, *value == opcodes::suspend );\n        }\n\n        return bluetoe::error_codes::success;\n    }\n\nprivate:\n    struct protocol_mode\n    {\n        enum protocol_mode_t : std::uint8_t\n        {\n            boot   = 0x00,\n            report = 0x01\n        };\n    };\n\n    struct opcodes\n    {\n        enum : std::uint8_t\n        {\n            suspend      = 0x00,\n            exit_suspend = 0x01\n        };\n    };\n\n    protocol_mode::protocol_mode_t       mode_;\n};\n\nusing battery_service = bluetoe::battery_level<\n    bluetoe::bas::handler< keyboard_handler >,\n    bluetoe::requires_encryption\n>;\n\nstatic constexpr char manufacturer_name[] = \"Torrox\";\nstatic constexpr char model_number[]      = \"Model 1\";\n\nusing device_info_service = bluetoe::device_information_service<\n    bluetoe::dis::manufacturer_name< manufacturer_name >,\n    bluetoe::dis::model_number< model_number >,\n    bluetoe::dis::pnp_id<\n        bluetoe::dis::vendor_id_source_t::bluetooth, 0x0269,\n        0x4711,\n        0x0000 >,\n    bluetoe::requires_encryption\n>;\n\nusing hid_service = bluetoe::service<\n    bluetoe::hid::service_uuid,\n    bluetoe::characteristic<\n        bluetoe::hid::protocol_mode_uuid,\n        bluetoe::mixin_write_handler< keyboard_handler, &keyboard_handler::protocol_mode_write_handler >,\n        bluetoe::mixin_read_handler< keyboard_handler, &keyboard_handler::protocol_mode_read_handler >,\n        bluetoe::only_write_without_response\n    >,\n    bluetoe::characteristic<\n        bluetoe::hid::report_uuid,\n        bluetoe::hid::input_report_reference< 0 >,\n        bluetoe::mixin_write_handler< keyboard_handler, &keyboard_handler::input_report_write_handler >,\n        bluetoe::mixin_read_handler< keyboard_handler, &keyboard_handler::input_report_read_handler >,\n        bluetoe::notify\n    >,\n    bluetoe::characteristic<\n        bluetoe::hid::report_uuid,\n        bluetoe::hid::output_report_reference< 0 >,\n        bluetoe::mixin_write_handler< keyboard_handler, &keyboard_handler::output_report_write_handler >,\n        bluetoe::mixin_read_handler< keyboard_handler, &keyboard_handler::output_report_read_handler >,\n        bluetoe::write_without_response\n    >,\n    bluetoe::characteristic<\n        bluetoe::hid::report_uuid,\n        bluetoe::hid::feature_report_reference< 0 >,\n        bluetoe::mixin_write_handler< keyboard_handler, &keyboard_handler::feature_report_write_handler >,\n        bluetoe::mixin_read_handler< keyboard_handler, &keyboard_handler::feature_report_read_handler >\n    >,\n    bluetoe::characteristic<\n        bluetoe::hid::report_map_uuid,\n        bluetoe::fixed_blob_value< report_map_data, sizeof( report_map_data ) >\n    >,\n    bluetoe::characteristic<\n        bluetoe::hid::boot_keyboard_input_report_uuid,\n        bluetoe::mixin_write_handler< keyboard_handler, &keyboard_handler::boot_input_write_handler >,\n        bluetoe::mixin_read_handler< keyboard_handler, &keyboard_handler::boot_input_read_handler >,\n        bluetoe::notify\n    >,\n    bluetoe::characteristic<\n        bluetoe::hid::boot_keyboard_output_report_uuid,\n        bluetoe::mixin_write_handler< keyboard_handler, &keyboard_handler::boot_output_write_handler >,\n        bluetoe::mixin_read_handler< keyboard_handler, &keyboard_handler::boot_output_read_handler >,\n        bluetoe::write_without_response\n    >,\n    bluetoe::characteristic<\n        bluetoe::hid::hid_information_uuid,\n        bluetoe::fixed_blob_value< hid_information, sizeof( hid_information ) >\n    >,\n    bluetoe::characteristic<\n        bluetoe::hid::hid_control_point_uuid,\n        bluetoe::mixin_write_handler< keyboard_handler, &keyboard_handler::control_point_write_handler >,\n        bluetoe::only_write_without_response\n    >,\n    bluetoe::requires_encryption\n>;\n\nstatic const char name[] = \"Bluetoe-Keyboard\";\n\nusing keyboard = bluetoe::server<\n    bluetoe::server_name< name >,\n    bluetoe::appearance::keyboard,\n    // by default, bluetoe would advertise all services\n    bluetoe::list_of_16_bit_service_uuids<\n        bluetoe::hid::service_uuid\n    >,\n    battery_service,\n    device_info_service,\n    hid_service,\n    bluetoe::mixin< keyboard_handler >\n>;\n\nbluetoe::device<\n    keyboard,\n    bluetoe::link_layer::advertising_interval< 30u > > server;\n\nint main()\n{\n    init_hardware();\n\n    for ( ;; )\n    {\n        server.run();\n    }\n}\n"
  },
  {
    "path": "examples/nrf51_toolchain_support/CMakeLists.txt",
    "content": "if(CMAKE_CROSSCOMPILING)\n    if (NOT DEFINED NRF5_SDK_ROOT)\n        message(FATAL_ERROR \"Please define NRF5_SDK_ROOT to point to your Nordic SDK installation!\")\n    endif()\n\n    # create an interface-only target to publish hardware specific options. Any target that\n    # requires the hardware specific options need only to depend on this target\n    add_library(toolchain_nrf51 INTERFACE)\n    add_library(toolchain::nrf51 ALIAS toolchain_nrf51)\n    target_include_directories(toolchain_nrf51 INTERFACE ${NRF5_SDK_ROOT}/components/device)\n    target_include_directories(toolchain_nrf51 INTERFACE ${NRF5_SDK_ROOT}/components/toolchain/cmsis/include)\n    target_include_directories(toolchain_nrf51 INTERFACE .)\n    target_compile_definitions(toolchain_nrf51 INTERFACE NRF51)\n\n    add_compile_definitions($<$<CONFIG:Debug>:BLUETOE_NRF51_RADIO_DEBUG>)\n\n    enable_language(ASM)\n    add_library(startup_nrf51 STATIC\n            gcc_startup_nrf51.s\n            system_nrf51422.c\n            )\n    target_link_libraries(startup_nrf51 PRIVATE toolchain::nrf51)\n    add_library(startup::nrf51 ALIAS startup_nrf51)\n\n    set_source_files_properties(\n            gcc_startup_nrf51.s\n            COMPILE_FLAGS \"-x assembler-with-cpp\")\n\n    add_custom_target(linker_script ALL\n            COMMAND ${CMAKE_COMMAND} -E\n            -MMD -MP -MT ${CMAKE_CURRENT_BINARY_DIR}/linker_script.ld -MF ${CMAKE_CURRENT_BINARY_DIR}/linker_script.ld\n            -o ${CMAKE_CURRENT_BINARY_DIR}/linker_script.ld\n            ${CMAKE_CURRENT_SOURCE_DIR}/nrf51_xxaa.ld\n            )\n\n    function(add_linker_script target)\n        # As the function gets called from expamples/CMakeLists.txt CMAKE_CURRENT_LIST_DIR and CMAKE_CURRENT_SOURCE_DIR\n        # is expamples/\n        set_property(\n            TARGET ${target}\n            APPEND\n            PROPERTY\n                INTERFACE_LINK_DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/nrf51_toolchain_support/linker_script.ld)\n\n        target_link_options(${target}\n            PRIVATE -T ${CMAKE_CURRENT_BINARY_DIR}/nrf51_toolchain_support/linker_script.ld)\n\n        add_dependencies(${target} linker_script)\n    endfunction()\n\n    if (DEFINED BLUETOE_JLINK)\n        message( WARNING \"nrfjprog ${BLUETOE_JLINK} selected\")\n        set(SELECT_JLINK_DEVICE --snr ${BLUETOE_JLINK} PARENT_SCOPE)\n    endif()\n\n    function(define_flash_command target)\n        add_custom_target(${target}.flash\n            COMMAND nrfjprog --chiperase --family NRF51 ${SELECT_JLINK_DEVICE} --program ${target}.hex --verify --reset\n            VERBATIM\n            )\n        add_dependencies(${target}.flash ${target}.artifacts)\n    endfunction()\n\nelse()\n    message(FATAL_ERROR \"Please set CMAKE_TOOLCHAIN_FILE to one of the tool-chain files in examples/cmake!\")\nendif()\n"
  },
  {
    "path": "examples/nrf51_toolchain_support/gcc_nrf51_common.ld",
    "content": "/* Linker script for Nordic Semiconductor nRF5 devices\r *\r * Version: Sourcery G++ 4.5-1\r * Support: https://support.codesourcery.com/GNUToolchain/\r *\r * Copyright (c) 2007, 2008, 2009, 2010 CodeSourcery, Inc.\r *\r * The authors hereby grant permission to use, copy, modify, distribute,\r * and license this software and its documentation for any purpose, provided\r * that existing copyright notices are retained in all copies and that this\r * notice is included verbatim in any distributions.  No written agreement,\r * license, or royalty fee is required for any of the authorized uses.\r * Modifications to this software may be copyrighted by their authors\r * and need not follow the licensing terms described here, provided that\r * the new terms are clearly indicated on the first page of each file where\r * they apply.\r */\rOUTPUT_FORMAT (\"elf32-littlearm\", \"elf32-bigarm\", \"elf32-littlearm\")\r\r/* Linker script to place sections and symbol values. Should be used together\r * with other linker script that defines memory regions FLASH and RAM.\r * It references following symbols, which must be defined in code:\r *   Reset_Handler : Entry of reset handler\r *\r * It defines following symbols, which code can use without definition:\r *   __exidx_start\r *   __exidx_end\r *   __etext\r *   __data_start__\r *   __preinit_array_start\r *   __preinit_array_end\r *   __init_array_start\r *   __init_array_end\r *   __fini_array_start\r *   __fini_array_end\r *   __data_end__\r *   __bss_start__\r *   __bss_end__\r *   __end__\r *   end\r *   __HeapLimit\r *   __StackLimit\r *   __StackTop\r *   __stack\r */\rENTRY(Reset_Handler)\r\rSECTIONS\r{\r\t.text :\r\t{\r\t\tKEEP(*(.Vectors))\r\t\t*(.text*)\r\r\t\tKEEP(*(.init))\r\t\tKEEP(*(.fini))\r\r\t\t/* .ctors */\r\t\t*crtbegin.o(.ctors)\r\t\t*crtbegin?.o(.ctors)\r\t\t*(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors)\r\t\t*(SORT(.ctors.*))\r\t\t*(.ctors)\r\r\t\t/* .dtors */\r \t\t*crtbegin.o(.dtors)\r \t\t*crtbegin?.o(.dtors)\r \t\t*(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors)\r \t\t*(SORT(.dtors.*))\r \t\t*(.dtors)\r\r\t\t*(.rodata*)\r\r\t\t*(.eh_frame*)\r\t\t. = ALIGN(4);\r\t} > FLASH\r\r\t.preinit_array     :\r\t{\r\t\tPROVIDE_HIDDEN (__preinit_array_start = .);\r\t\tKEEP (*(.preinit_array*))\r\t\tPROVIDE_HIDDEN (__preinit_array_end = .);\r\t} >FLASH\r\r\t.init_array :\r\t{\r\t\tPROVIDE_HIDDEN (__init_array_start = .);\r\t\tKEEP (*(SORT(.init_array.*)))\r\t\tKEEP (*(.init_array*))\r\t\tPROVIDE_HIDDEN (__init_array_end = .);\r\t} >FLASH\r\r\t.fini_array :\r\t{\r\t\tPROVIDE_HIDDEN (__fini_array_start = .);\r\t\t/* No need to finalise\r\t\tKEEP (*(SORT(.fini_array.*)))\r\t\tKEEP (*(.fini_array*))\r\t\t*/\r\t\tPROVIDE_HIDDEN (__fini_array_end = .);\r\t} >FLASH\r\r\t.ARM.extab :\r\t{\r\t\t*(.ARM.extab* .gnu.linkonce.armextab.*)\r\t\t. = ALIGN(4);\r\t} > FLASH\r\r\t__exidx_start = .;\r\t.ARM.exidx :\r\t{\r\t\t*(.ARM.exidx* .gnu.linkonce.armexidx.*)\r\t\t. = ALIGN(4);\r\t} > FLASH\r\t__exidx_end = .;\r\r\t__etext = .;\r\r\t.data : AT (__etext)\r\t{\r\t\t__data_start__ = .;\r\t\t*(vtable)\r\t\t*(.data*)\r\r\t\t*(.jcr)\r\t\t. = ALIGN(4);\r\t\t/* All data end */\r\t\t__data_end__ = .;\r\r\t} > RAM\r\r\t.bss :\r\t{\r\t\t. = ALIGN(4);\r\t\t__bss_start__ = .;\r\t\t*(.bss*)\r\t\t*(COMMON)\r\t\t. = ALIGN(4);\r\t\t__bss_end__ = .;\r\t} > RAM\r\r\t.heap (COPY):\r\t{\r\t\t__end__ = .;\r\t\tend = __end__;\r\t\t*(.heap*)\r\t\t__HeapLimit = .;\r\t} > RAM\r\r\t/* .stack_dummy section doesn't contains any symbols. It is only\r\t * used for linker to calculate size of stack sections, and assign\r\t * values to stack symbols later */\r\t.stack_dummy (COPY):\r\t{\r\t\t*(.stack*)\r\t} > RAM\r\r\t/* Set stack top to end of RAM, and stack limit move down by\r\t * size of stack_dummy section */\r\t__StackTop = ORIGIN(RAM) + LENGTH(RAM);\r\t__StackLimit = __StackTop - SIZEOF(.stack_dummy);\r\tPROVIDE(__stack = __StackTop);\r\r\t/* Check if data + heap + stack exceeds RAM limit */\r\tASSERT(__StackLimit >= __HeapLimit, \"region RAM overflowed with stack\")\r}\r\r"
  },
  {
    "path": "examples/nrf51_toolchain_support/gcc_startup_nrf51.s",
    "content": "/*\nCopyright (c) 2015, Nordic Semiconductor ASA\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\n* Neither the name of Nordic Semiconductor ASA nor the names of its\n  contributors may be used to endorse or promote products derived from\n  this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n/*\nNOTE: Template files (including this one) are application specific and therefore\nexpected to be copied into the application project folder prior to its use!\n*/\n\n    .syntax unified\n    .arch armv6-m\n\n    .section .stack\n    .align 3\n#ifdef __STACK_SIZE\n    .equ    Stack_Size, __STACK_SIZE\n#else\n    .equ    Stack_Size, 2048\n#endif\n    .globl    __StackTop\n    .globl    __StackLimit\n__StackLimit:\n    .space    Stack_Size\n    .size __StackLimit, . - __StackLimit\n__StackTop:\n    .size __StackTop, . - __StackTop\n\n    .section .heap\n    .align 3\n#ifdef __HEAP_SIZE\n    .equ    Heap_Size, __HEAP_SIZE\n#else\n    .equ    Heap_Size, 0\n#endif\n    .globl    __HeapBase\n    .globl    __HeapLimit\n__HeapBase:\n    .if    Heap_Size\n    .space    Heap_Size\n    .endif\n    .size __HeapBase, . - __HeapBase\n__HeapLimit:\n    .size __HeapLimit, . - __HeapLimit\n\n    .section .Vectors\n    .align 2\n    .globl __Vectors\n__Vectors:\n    .long    __StackTop            /* Top of Stack */\n    .long   Reset_Handler               /* Reset Handler */\n    .long   NMI_Handler                 /* NMI Handler */\n    .long   HardFault_Handler           /* Hard Fault Handler */\n    .long   0                           /* Reserved */\n    .long   0                           /* Reserved */\n    .long   0                           /* Reserved */\n    .long   0                           /* Reserved */\n    .long   0                           /* Reserved */\n    .long   0                           /* Reserved */\n    .long   0                           /* Reserved */\n    .long   SVC_Handler                 /* SVCall Handler */\n    .long   0                           /* Reserved */\n    .long   0                           /* Reserved */\n    .long   PendSV_Handler              /* PendSV Handler */\n    .long   SysTick_Handler             /* SysTick Handler */\n\n  /* External Interrupts */\n    .long   POWER_CLOCK_IRQHandler\n    .long   RADIO_IRQHandler\n    .long   UART0_IRQHandler\n    .long   SPI0_TWI0_IRQHandler\n    .long   SPI1_TWI1_IRQHandler\n    .long   0                         /*Reserved */\n    .long   GPIOTE_IRQHandler\n    .long   ADC_IRQHandler\n    .long   TIMER0_IRQHandler\n    .long   TIMER1_IRQHandler\n    .long   TIMER2_IRQHandler\n    .long   RTC0_IRQHandler\n    .long   TEMP_IRQHandler\n    .long   RNG_IRQHandler\n    .long   ECB_IRQHandler\n    .long   CCM_AAR_IRQHandler\n    .long   WDT_IRQHandler\n    .long   RTC1_IRQHandler\n    .long   QDEC_IRQHandler\n    .long   LPCOMP_IRQHandler\n    .long   SWI0_IRQHandler\n    .long   SWI1_IRQHandler\n    .long   SWI2_IRQHandler\n    .long   SWI3_IRQHandler\n    .long   SWI4_IRQHandler\n    .long   SWI5_IRQHandler\n    .long   0                         /*Reserved */\n    .long   0                         /*Reserved */\n    .long   0                         /*Reserved */\n    .long   0                         /*Reserved */\n    .long   0                         /*Reserved */\n    .long   0                         /*Reserved */\n\n    .size    __Vectors, . - __Vectors\n\n/* Reset Handler */\n\n    .equ    NRF_POWER_RAMON_ADDRESS,             0x40000524\n    .equ    NRF_POWER_RAMONB_ADDRESS,            0x40000554\n    .equ    NRF_POWER_RAMONx_RAMxON_ONMODE_Msk,  0x3\n\n    .text\n    .thumb\n    .thumb_func\n    .align 1\n    .globl    Reset_Handler\n    .type    Reset_Handler, %function\nReset_Handler:\n    .fnstart\n\n/* Make sure ALL RAM banks are powered on */\n    MOVS    R1, #NRF_POWER_RAMONx_RAMxON_ONMODE_Msk\n\n    LDR     R0, =NRF_POWER_RAMON_ADDRESS\n    LDR     R2, [R0]\n    ORRS    R2, R1\n    STR     R2, [R0]\n\n    LDR     R0, =NRF_POWER_RAMONB_ADDRESS\n    LDR     R2, [R0]\n    ORRS    R2, R1\n    STR     R2, [R0]\n\n/*     Loop to copy data from read only memory to RAM. The ranges\n *      of copy from/to are specified by following symbols evaluated in\n *      linker script.\n *      __etext: End of code section, i.e., begin of data sections to copy from.\n *      __data_start__/__data_end__: RAM address range that data should be\n *      copied to. Both must be aligned to 4 bytes boundary.  */\n\n    ldr    r1, =__etext\n    ldr    r2, =__data_start__\n    ldr    r3, =__data_end__\n\n    subs    r3, r2\n    ble     .LC0\n\n.LC1:\n    subs    r3, 4\n    ldr    r0, [r1,r3]\n    str    r0, [r2,r3]\n    bgt    .LC1\n.LC0:\n\n    LDR     R0, =SystemInit\n    BLX     R0\n    LDR     R0, =_start\n    BX      R0\n\n    .pool\n    .cantunwind\n    .fnend\n    .size   Reset_Handler,.-Reset_Handler\n\n    .section \".text\"\n\n\n/* Dummy Exception Handlers (infinite loops which can be modified) */\n\n    .weak   NMI_Handler\n    .type   NMI_Handler, %function\nNMI_Handler:\n    B       .\n    .size   NMI_Handler, . - NMI_Handler\n\n\n    .weak   HardFault_Handler\n    .type   HardFault_Handler, %function\nHardFault_Handler:\n    B       .\n    .size   HardFault_Handler, . - HardFault_Handler\n\n\n    .weak   SVC_Handler\n    .type   SVC_Handler, %function\nSVC_Handler:\n    B       .\n    .size   SVC_Handler, . - SVC_Handler\n\n\n    .weak   PendSV_Handler\n    .type   PendSV_Handler, %function\nPendSV_Handler:\n    B       .\n    .size   PendSV_Handler, . - PendSV_Handler\n\n\n    .weak   SysTick_Handler\n    .type   SysTick_Handler, %function\nSysTick_Handler:\n    B       .\n    .size   SysTick_Handler, . - SysTick_Handler\n\n\n/* IRQ Handlers */\n\n    .globl  Default_Handler\n    .type   Default_Handler, %function\nDefault_Handler:\n    B       .\n    .size   Default_Handler, . - Default_Handler\n\n    .macro  IRQ handler\n    .weak   \\handler\n    .set    \\handler, Default_Handler\n    .endm\n\n    IRQ  POWER_CLOCK_IRQHandler\n    IRQ  RADIO_IRQHandler\n    IRQ  UART0_IRQHandler\n    IRQ  SPI0_TWI0_IRQHandler\n    IRQ  SPI1_TWI1_IRQHandler\n    IRQ  GPIOTE_IRQHandler\n    IRQ  ADC_IRQHandler\n    IRQ  TIMER0_IRQHandler\n    IRQ  TIMER1_IRQHandler\n    IRQ  TIMER2_IRQHandler\n    IRQ  RTC0_IRQHandler\n    IRQ  TEMP_IRQHandler\n    IRQ  RNG_IRQHandler\n    IRQ  ECB_IRQHandler\n    IRQ  CCM_AAR_IRQHandler\n    IRQ  WDT_IRQHandler\n    IRQ  RTC1_IRQHandler\n    IRQ  QDEC_IRQHandler\n    IRQ  LPCOMP_IRQHandler\n    IRQ  SWI0_IRQHandler\n    IRQ  SWI1_IRQHandler\n    IRQ  SWI2_IRQHandler\n    IRQ  SWI3_IRQHandler\n    IRQ  SWI4_IRQHandler\n    IRQ  SWI5_IRQHandler\n\n  .end\n"
  },
  {
    "path": "examples/nrf51_toolchain_support/nrf51_xxaa.ld",
    "content": "/* Linker script to configure memory regions. */\n\nGROUP(-lgcc -lc -lnosys)\n\nMEMORY\n{\n    FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 0x40000\n    NRF_UICR (rw)       : ORIGIN = 0x10001000, LENGTH = 256\n    RAM (rwx) :  ORIGIN = 0x20000000, LENGTH = 0x4000\n}\n\nPROVIDE(__flash_start__ = ORIGIN(FLASH));\nPROVIDE(__flash_length__ = LENGTH(FLASH));\nPROVIDE(__flash_end__ = ORIGIN(FLASH) + LENGTH(FLASH));\n\n#include \"gcc_nrf51_common.ld\"\n\n"
  },
  {
    "path": "examples/nrf51_toolchain_support/platform.cmake",
    "content": "if(CMAKE_CROSSCOMPILING)\n    # set global compile options that depend on hardware and must apply to\n    # all targets of the project\n    add_compile_options(-mcpu=cortex-m0 -mthumb)\n    add_compile_options(-mabi=aapcs)\n    # when cmake's 3.13 is released we'll replace this with add_linker_options()\n    set(CMAKE_EXE_LINKER_FLAGS \"${CMAKE_EXE_LINKER_FLAGS} -mcpu=cortex-m0 -mthumb -mabi=aapcs\")\nelse()\n    message(error \"\")\nendif()\n"
  },
  {
    "path": "examples/nrf51_toolchain_support/system_nrf51.h",
    "content": "/* Copyright (c) 2015, Nordic Semiconductor ASA\r\n * All rights reserved.\r\n *\r\n * Redistribution and use in source and binary forms, with or without\r\n * modification, are permitted provided that the following conditions are met:\r\n *\r\n *   * Redistributions of source code must retain the above copyright notice, this\r\n *     list of conditions and the following disclaimer.\r\n *\r\n *   * Redistributions in binary form must reproduce the above copyright notice,\r\n *     this list of conditions and the following disclaimer in the documentation\r\n *     and/or other materials provided with the distribution.\r\n *\r\n *   * Neither the name of Nordic Semiconductor ASA nor the names of its\r\n *     contributors may be used to endorse or promote products derived from\r\n *     this software without specific prior written permission.\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\r\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\r\n * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\r\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\r\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\r\n * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\r\n * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\r\n * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\r\n * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r\n *\r\n */\r\n\r\n#ifndef SYSTEM_NRF51_H\r\n#define SYSTEM_NRF51_H\r\n\r\n#ifdef __cplusplus\r\nextern \"C\" {\r\n#endif\r\n\r\n#include <stdint.h>\r\n\r\n\r\nextern uint32_t SystemCoreClock;    /*!< System Clock Frequency (Core Clock)  */\r\n\r\n/**\r\n * Initialize the system\r\n *\r\n * @param  none\r\n * @return none\r\n *\r\n * @brief  Setup the microcontroller system.\r\n *         Initialize the System and update the SystemCoreClock variable.\r\n */\r\nextern void SystemInit (void);\r\n\r\n/**\r\n * Update SystemCoreClock variable\r\n *\r\n * @param  none\r\n * @return none\r\n *\r\n * @brief  Updates the SystemCoreClock with current core Clock \r\n *         retrieved from cpu registers.\r\n */\r\nextern void SystemCoreClockUpdate (void);\r\n\r\n#ifdef __cplusplus\r\n}\r\n#endif\r\n\r\n#endif /* SYSTEM_NRF51_H */\r\n"
  },
  {
    "path": "examples/nrf51_toolchain_support/system_nrf51422.c",
    "content": "/* Copyright (c) 2013, Nordic Semiconductor ASA\r\n * All rights reserved.\r\n *\r\n * Redistribution and use in source and binary forms, with or without\r\n * modification, are permitted provided that the following conditions are met:\r\n *\r\n *   * Redistributions of source code must retain the above copyright notice, this\r\n *     list of conditions and the following disclaimer.\r\n *\r\n *   * Redistributions in binary form must reproduce the above copyright notice,\r\n *     this list of conditions and the following disclaimer in the documentation\r\n *     and/or other materials provided with the distribution.\r\n *\r\n *   * Neither the name of Nordic Semiconductor ASA nor the names of its\r\n *     contributors may be used to endorse or promote products derived from\r\n *     this software without specific prior written permission.\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\r\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\r\n * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\r\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\r\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\r\n * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\r\n * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\r\n * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\r\n * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r\n *\r\n */\r\n\r\n/* NOTE: Template files (including this one) are application specific and therefore expected to \r\n   be copied into the application project folder prior to its use! */\r\n\r\n#include <stdint.h>\r\n#include <stdbool.h>\r\n#include \"nrf.h\"\r\n#include \"system_nrf51.h\"\r\n\r\n/*lint ++flb \"Enter library region\" */\r\n\r\n\r\n#define __SYSTEM_CLOCK      (16000000UL)     /*!< nRF51 devices use a fixed System Clock Frequency of 16MHz */\r\n\r\nstatic bool is_manual_peripheral_setup_needed(void);\r\nstatic bool is_disabled_in_debug_needed(void);\r\n\r\n\r\n#if defined ( __CC_ARM )\r\n    uint32_t SystemCoreClock __attribute__((used)) = __SYSTEM_CLOCK;  \r\n#elif defined ( __ICCARM__ )\r\n    __root uint32_t SystemCoreClock = __SYSTEM_CLOCK;\r\n#elif defined   ( __GNUC__ )\r\n    uint32_t SystemCoreClock __attribute__((used)) = __SYSTEM_CLOCK;\r\n#endif\r\n\r\nvoid SystemCoreClockUpdate(void)\r\n{\r\n    SystemCoreClock = __SYSTEM_CLOCK;\r\n}\r\n\r\nvoid SystemInit(void)\r\n{\r\n    /* If desired, switch off the unused RAM to lower consumption by the use of RAMON register.\r\n       It can also be done in the application main() function. */\r\n\r\n    /* Prepare the peripherals for use as indicated by the PAN 26 \"System: Manual setup is required\r\n       to enable the use of peripherals\" found at Product Anomaly document for your device found at\r\n       https://www.nordicsemi.com/. The side effect of executing these instructions in the devices \r\n       that do not need it is that the new peripherals in the second generation devices (LPCOMP for\r\n       example) will not be available. */\r\n    if (is_manual_peripheral_setup_needed())\r\n    {\r\n        *(uint32_t volatile *)0x40000504 = 0xC007FFDF;\r\n        *(uint32_t volatile *)0x40006C18 = 0x00008000;\r\n    }\r\n    \r\n    /* Disable PROTENSET registers under debug, as indicated by PAN 59 \"MPU: Reset value of DISABLEINDEBUG\r\n       register is incorrect\" found at Product Anomaly document four your device found at \r\n       https://www.nordicsemi.com/. There is no side effect of using these instruction if not needed. */\r\n    if (is_disabled_in_debug_needed())\r\n    {\r\n        NRF_MPU->DISABLEINDEBUG = MPU_DISABLEINDEBUG_DISABLEINDEBUG_Disabled << MPU_DISABLEINDEBUG_DISABLEINDEBUG_Pos;\r\n    }\r\n}\r\n\r\n\r\nstatic bool is_manual_peripheral_setup_needed(void) \r\n{\r\n    if ((((*(uint32_t *)0xF0000FE0) & 0x000000FF) == 0x1) && (((*(uint32_t *)0xF0000FE4) & 0x0000000F) == 0x0))\r\n    {\r\n        if ((((*(uint32_t *)0xF0000FE8) & 0x000000F0) == 0x00) && (((*(uint32_t *)0xF0000FEC) & 0x000000F0) == 0x0))\r\n        {\r\n            return true;\r\n        }\r\n        if ((((*(uint32_t *)0xF0000FE8) & 0x000000F0) == 0x10) && (((*(uint32_t *)0xF0000FEC) & 0x000000F0) == 0x0))\r\n        {\r\n            return true;\r\n        }\r\n        if ((((*(uint32_t *)0xF0000FE8) & 0x000000F0) == 0x30) && (((*(uint32_t *)0xF0000FEC) & 0x000000F0) == 0x0))\r\n        {\r\n            return true;\r\n        }\r\n    }\r\n    \r\n    return false;\r\n}\r\n\r\nstatic bool is_disabled_in_debug_needed(void) \r\n{\r\n    if ((((*(uint32_t *)0xF0000FE0) & 0x000000FF) == 0x1) && (((*(uint32_t *)0xF0000FE4) & 0x0000000F) == 0x0))\r\n    {\r\n        if ((((*(uint32_t *)0xF0000FE8) & 0x000000F0) == 0x40) && (((*(uint32_t *)0xF0000FEC) & 0x000000F0) == 0x0))\r\n        {\r\n            return true;\r\n        }\r\n    }\r\n    \r\n    return false;\r\n}\r\n\r\n/*lint --flb \"Leave library region\" */\r\n"
  },
  {
    "path": "examples/nrf52_high_cpu_load.cpp",
    "content": "/*\n * Example to prove, that the nrf52 binding is robust to miss some connection events due to\n * high CPU load.\n */\n\n#include <bluetoe/server.hpp>\n#include <bluetoe/device.hpp>\n#include <bluetoe/gatt_options.hpp>\n#include <nrf.h>\n\nusing namespace bluetoe;\n\n// LED1 on a nRF52 eval board\nstatic constexpr int io_pin = 30;\n\nstatic std::uint8_t io_pin_write_handler( bool state )\n{\n    // on an nRF52 eval board, the pin is connected to the LED's cathode, this inverts the logic.\n    NRF_GPIO->OUT = state\n        ? NRF_GPIO->OUT & ~( 1 << io_pin )\n        : NRF_GPIO->OUT | ( 1 << io_pin );\n\n    return error_codes::success;\n}\n\nusing blinky_server = server<\n    service<\n        service_uuid< 0xC11169E1, 0x6252, 0x4450, 0x931C, 0x1B43A318783B >,\n        characteristic<\n            requires_encryption,\n            free_write_handler< bool, io_pin_write_handler >\n        >\n    >,\n    max_mtu_size< 65 >\n>;\n\nstatic constexpr std::uint32_t in_callback_io_pin = 30;\nstatic NRF_TIMER_Type& delay_timer = *NRF_TIMER1;\n\nstatic void init_hardware()\n{\n    NRF_GPIO->PIN_CNF[ in_callback_io_pin ] =\n        ( GPIO_PIN_CNF_DRIVE_S0H1 << GPIO_PIN_CNF_DRIVE_Pos ) |\n        ( GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos );\n\n    NRF_GPIO->OUTCLR = ( 1 << in_callback_io_pin );\n\n    delay_timer.PRESCALER = 4; // results in a clock of 16Mz / 2^4 == 1MHz\n    delay_timer.BITMODE   = TIMER_BITMODE_BITMODE_32Bit;\n    delay_timer.SHORTS    =\n        ( TIMER_SHORTS_COMPARE0_STOP_Enabled << TIMER_SHORTS_COMPARE0_STOP_Pos )\n      | ( TIMER_SHORTS_COMPARE0_CLEAR_Enabled << TIMER_SHORTS_COMPARE0_CLEAR_Pos );\n\n    delay_timer.TASKS_STOP = 1;\n    delay_timer.EVENTS_COMPARE[0] = 0;\n\n    // disable cache\n//    NRF_NVMC->ICACHECNF = 0;\n    // Disable Blockprotection\n//    NRF_BPROT->DISABLEINDEBUG = BPROT_DISABLEINDEBUG_DISABLEINDEBUG_Msk;\n}\n\ntemplate < typename T >\nstruct load_connection_event_callback\n{\n    static void call_connection_event_callback( const bluetoe::link_layer::delta_time& time_till_next_event );\n\n    using meta_type = bluetoe::link_layer::details::connection_event_callback_meta_type;\n};\n\n\ndevice<\n    blinky_server,\n    security_manager,\n    bluetoe::nrf::calibrated_rc_sleep_clock,\n    bluetoe::nrf::high_frequency_crystal_oscillator_startup_time< 1000 >,\n    link_layer::buffer_sizes< 200, 200 >,\n    link_layer::sleep_clock_accuracy_ppm< 500 >,\n    load_connection_event_callback< blinky_server >\n > gatt_srv;\n\ntemplate < typename T >\nvoid load_connection_event_callback< T >::call_connection_event_callback( const bluetoe::link_layer::delta_time& /* time_till_next_event */ )\n{\n    NRF_GPIO->OUTSET = ( 1 << in_callback_io_pin );\n\n    static int count = 0;\n\n    ++count;\n\n    // every once in a while lets consume more CPU time than time_till_next_event\n    if ( count == 5 )\n    {\n        delay_timer.CC[ 0 ] = 80 * 1000;\n        delay_timer.TASKS_START = 1;\n\n        for ( ; !delay_timer.EVENTS_COMPARE[0] ; )\n            ;\n\n        delay_timer.EVENTS_COMPARE[0] = 0;\n    }\n    // Or lets utilize / stop the CPU by eraseing a flash page\n    else if ( count == 100 )\n    {\n        count = 0;\n        gatt_srv.nrf_flash_memory_access_begin();\n\n        while ( NRF_NVMC->READY == NVMC_READY_READY_Busy )\n            ;\n\n        NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Een;\n        __ISB();\n        __DSB();\n\n        NRF_NVMC->ERASEPAGE = 0x20000;\n\n        while ( NRF_NVMC->READY == NVMC_READY_READY_Busy )\n            ;\n\n        gatt_srv.nrf_flash_memory_access_end();\n    }\n\n    NRF_GPIO->OUTCLR = ( 1 << in_callback_io_pin );\n}\n\nint main()\n{\n    init_hardware();\n\n    // Init GPIO pin\n    NRF_GPIO->PIN_CNF[ io_pin ] =\n        ( GPIO_PIN_CNF_DRIVE_S0H1 << GPIO_PIN_CNF_DRIVE_Pos ) |\n        ( GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos );\n\n    for ( ;; )\n        gatt_srv.run();\n}\n"
  },
  {
    "path": "examples/nrf52_toolchain_support/CMakeLists.txt",
    "content": "if(CMAKE_CROSSCOMPILING)\n    if (NOT DEFINED NRF5_SDK_ROOT)\n        message(FATAL_ERROR \"Please define NRF5_SDK_ROOT to point to your Nordic SDK installation!\")\n    endif()\n\n    # create an interface-only target to publish hardware specific options. Any target that\n    # requires the hardware specific options need only to depend on this target\n    add_library(toolchain_nrf52 INTERFACE)\n    add_library(toolchain::nrf52 ALIAS toolchain_nrf52)\n    target_include_directories(toolchain_nrf52 INTERFACE ${NRF5_SDK_ROOT}/modules/nrfx/mdk)\n    target_include_directories(toolchain_nrf52 INTERFACE ${NRF5_SDK_ROOT}/components/toolchain/cmsis/include)\n    target_include_directories(toolchain_nrf52 INTERFACE .)\n#    target_compile_definitions(toolchain_nrf52 INTERFACE NRF52 NRF52832_XXAA)\n    target_compile_definitions(toolchain_nrf52 INTERFACE NRF52820_XXAA)\n    target_compile_definitions(toolchain_nrf52 INTERFACE $<$<CONFIG:Debug>:BLUETOE_NRF52_RADIO_DEBUG>)\n\n    enable_language(ASM)\n    add_library(startup_nrf52 STATIC\n            gcc_startup_nrf52.s\n            system_nrf52.c\n            )\n    target_link_libraries(startup_nrf52 PRIVATE toolchain::nrf52)\n    add_library(startup::nrf52 ALIAS startup_nrf52)\n\n    set_source_files_properties(\n            gcc_startup_nrf52.s\n            COMPILE_FLAGS \"-x assembler-with-cpp\")\n\n    add_custom_target(linker_script ALL\n            COMMAND ${CMAKE_C_COMPILER} -E -P -x c\n            -MMD -MP -MT ${CMAKE_CURRENT_BINARY_DIR}/linker_script.ld -MF ${CMAKE_CURRENT_BINARY_DIR}/linker_script.ld\n            -o ${CMAKE_CURRENT_BINARY_DIR}/linker_script.ld\n            ${CMAKE_CURRENT_SOURCE_DIR}/nrf52.ld)\n\n    function(add_linker_script target)\n        # As the function gets called from expamples/CMakeLists.txt CMAKE_CURRENT_LIST_DIR and CMAKE_CURRENT_SOURCE_DIR\n        # is expamples/\n        set_property(\n            TARGET ${target}\n            APPEND\n            PROPERTY\n                INTERFACE_LINK_DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/nrf52_toolchain_support/linker_script.ld)\n\n        target_link_options(${target}\n            PRIVATE -T ${CMAKE_CURRENT_BINARY_DIR}/nrf52_toolchain_support/linker_script.ld)\n\n        add_dependencies(${target} linker_script)\n    endfunction()\n\n    if (DEFINED BLUETOE_JLINK)\n        message( WARNING \"nrfjprog ${BLUETOE_JLINK} selected\")\n        set(SELECT_JLINK_DEVICE --snr ${BLUETOE_JLINK} PARENT_SCOPE)\n    endif()\n\n    function(define_flash_command target)\n        add_custom_target(${target}.flash\n            COMMAND nrfjprog --chiperase --family NRF52 ${SELECT_JLINK_DEVICE} --program ${target}.hex --verify --reset\n            VERBATIM\n            )\n        add_dependencies(${target}.flash ${target}.artifacts)\n    endfunction()\n\nelse()\n    message(FATAL_ERROR \"Please set CMAKE_TOOLCHAIN_FILE to one of the tool-chain files in examples/cmake!\")\nendif()\n"
  },
  {
    "path": "examples/nrf52_toolchain_support/gcc_nrf5x_common.ld",
    "content": "/* Linker script for Nordic Semiconductor nRF5 devices\r *\r * Version: Sourcery G++ 4.5-1\r * Support: https://support.codesourcery.com/GNUToolchain/\r *\r * Copyright (c) 2007, 2008, 2009, 2010 CodeSourcery, Inc.\r *\r * The authors hereby grant permission to use, copy, modify, distribute,\r * and license this software and its documentation for any purpose, provided\r * that existing copyright notices are retained in all copies and that this\r * notice is included verbatim in any distributions.  No written agreement,\r * license, or royalty fee is required for any of the authorized uses.\r * Modifications to this software may be copyrighted by their authors\r * and need not follow the licensing terms described here, provided that\r * the new terms are clearly indicated on the first page of each file where\r * they apply.\r */\rOUTPUT_FORMAT (\"elf32-littlearm\", \"elf32-bigarm\", \"elf32-littlearm\")\r\r/* Linker script to place sections and symbol values. Should be used together\r * with other linker script that defines memory regions FLASH and RAM.\r * It references following symbols, which must be defined in code:\r *   Reset_Handler : Entry of reset handler\r *\r * It defines following symbols, which code can use without definition:\r *   __exidx_start\r *   __exidx_end\r *   __etext\r *   __data_start__\r *   __preinit_array_start\r *   __preinit_array_end\r *   __init_array_start\r *   __init_array_end\r *   __fini_array_start\r *   __fini_array_end\r *   __data_end__\r *   __bss_start__\r *   __bss_end__\r *   __end__\r *   end\r *   __HeapLimit\r *   __StackLimit\r *   __StackTop\r *   __stack\r */\rENTRY(Reset_Handler)\r\rSECTIONS\r{\r\t.text :\r\t{\r\t\tKEEP(*(.Vectors))\r\t\t*(.text*)\r\r\t\tKEEP(*(.init))\r\t\tKEEP(*(.fini))\r\r\t\t/* .ctors */\r\t\t*crtbegin.o(.ctors)\r\t\t*crtbegin?.o(.ctors)\r\t\t*(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors)\r\t\t*(SORT(.ctors.*))\r\t\t*(.ctors)\r\r\t\t/* .dtors */\r \t\t*crtbegin.o(.dtors)\r \t\t*crtbegin?.o(.dtors)\r \t\t*(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors)\r \t\t*(SORT(.dtors.*))\r \t\t*(.dtors)\r\r\t\t*(.rodata*)\r\r\t\t*(.eh_frame*)\r\t\t. = ALIGN(4);\r\t} > FLASH\r\r\t.preinit_array     :\r\t{\r\t\tPROVIDE_HIDDEN (__preinit_array_start = .);\r\t\tKEEP (*(.preinit_array*))\r\t\tPROVIDE_HIDDEN (__preinit_array_end = .);\r\t} >FLASH\r\r\t.init_array :\r\t{\r\t\tPROVIDE_HIDDEN (__init_array_start = .);\r\t\tKEEP (*(SORT(.init_array.*)))\r\t\tKEEP (*(.init_array*))\r\t\tPROVIDE_HIDDEN (__init_array_end = .);\r\t} >FLASH\r\r\t.fini_array :\r\t{\r\t\tPROVIDE_HIDDEN (__fini_array_start = .);\r\t\t/* No need to finalise\r\t\tKEEP (*(SORT(.fini_array.*)))\r\t\tKEEP (*(.fini_array*))\r\t\t*/\r\t\tPROVIDE_HIDDEN (__fini_array_end = .);\r\t} >FLASH\r\r\t.ARM.extab :\r\t{\r\t\t*(.ARM.extab* .gnu.linkonce.armextab.*)\r\t\t. = ALIGN(4);\r\t} > FLASH\r\r\t__exidx_start = .;\r\t.ARM.exidx :\r\t{\r\t\t*(.ARM.exidx* .gnu.linkonce.armexidx.*)\r\t\t. = ALIGN(4);\r\t} > FLASH\r\t__exidx_end = .;\r\r\t__etext = .;\r\r\t.data : AT (__etext)\r\t{\r\t\t__data_start__ = .;\r\t\t*(vtable)\r\t\t*(.data*)\r\r\t\t*(.jcr)\r\t\t. = ALIGN(4);\r\t\t/* All data end */\r\t\t__data_end__ = .;\r\r\t} > RAM\r\r\t.bss :\r\t{\r\t\t. = ALIGN(4);\r\t\t__bss_start__ = .;\r\t\t*(.bss*)\r\t\t*(COMMON)\r\t\t. = ALIGN(4);\r\t\t__bss_end__ = .;\r\t} > RAM\r\r\t.heap (COPY):\r\t{\r\t\t__end__ = .;\r\t\tend = __end__;\r\t\t*(.heap*)\r\t\t__HeapLimit = .;\r\t} > RAM\r\r\t/* .stack_dummy section doesn't contains any symbols. It is only\r\t * used for linker to calculate size of stack sections, and assign\r\t * values to stack symbols later */\r\t.stack_dummy (COPY):\r\t{\r\t\t*(.stack*)\r\t} > RAM\r\r\t/* Set stack top to end of RAM, and stack limit move down by\r\t * size of stack_dummy section */\r\t__StackTop = ORIGIN(RAM) + LENGTH(RAM);\r\t__StackLimit = __StackTop - SIZEOF(.stack_dummy);\r\tPROVIDE(__stack = __StackTop);\r\r\t/* Check if data + heap + stack exceeds RAM limit */\r\tASSERT(__StackLimit >= __HeapLimit, \"region RAM overflowed with stack\")\r}\r\r"
  },
  {
    "path": "examples/nrf52_toolchain_support/gcc_startup_nrf52.s",
    "content": "/* \r\nCopyright (c) 2015, Nordic Semiconductor ASA\r\nAll rights reserved.\r\n\r\nRedistribution and use in source and binary forms, with or without\r\nmodification, are permitted provided that the following conditions are met:\r\n\r\n* Redistributions of source code must retain the above copyright notice, this\r\n  list of conditions and the following disclaimer.\r\n\r\n* Redistributions in binary form must reproduce the above copyright notice,\r\n  this list of conditions and the following disclaimer in the documentation\r\n  and/or other materials provided with the distribution.\r\n\r\n* Neither the name of Nordic Semiconductor ASA nor the names of its\r\n  contributors may be used to endorse or promote products derived from\r\n  this software without specific prior written permission.\r\n\r\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\r\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\r\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\r\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\r\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\r\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\r\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\r\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\r\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r\n*/\r\n\r\n/* \r\nNOTE: Template files (including this one) are application specific and therefore \r\nexpected to be copied into the application project folder prior to its use!\r\n*/\r\n\r\n    .syntax unified\r\n    .arch armv6-m\r\n\r\n    .section .stack\r\n    .align 3\r\n#ifdef __STACK_SIZE\r\n    .equ    Stack_Size, __STACK_SIZE\r\n#else\r\n    .equ    Stack_Size, 8192\r\n#endif\r\n    .globl    __StackTop\r\n    .globl    __StackLimit\r\n__StackLimit:\r\n    .space    Stack_Size\r\n    .size __StackLimit, . - __StackLimit\r\n__StackTop:\r\n    .size __StackTop, . - __StackTop\r\n\r\n    .section .heap\r\n    .align 3\r\n#ifdef __HEAP_SIZE\r\n    .equ    Heap_Size, __HEAP_SIZE\r\n#else\r\n    .equ    Heap_Size, 8192\r\n#endif\r\n    .globl    __HeapBase\r\n    .globl    __HeapLimit\r\n__HeapBase:\r\n    .if    Heap_Size\r\n    .space    Heap_Size\r\n    .endif\r\n    .size __HeapBase, . - __HeapBase\r\n__HeapLimit:\r\n    .size __HeapLimit, . - __HeapLimit\r\n    \r\n    .section .Vectors\r\n    .align 2\r\n    .globl __Vectors\r\n__Vectors:\r\n    .long    __StackTop            /* Top of Stack */\r\n    .long   Reset_Handler               /* Reset Handler */\r\n    .long   NMI_Handler                 /* NMI Handler */\r\n    .long   HardFault_Handler           /* Hard Fault Handler */\r\n    .long   0                           /* Reserved */\r\n    .long   0                           /* Reserved */\r\n    .long   0                           /* Reserved */\r\n    .long   0                           /* Reserved */\r\n    .long   0                           /* Reserved */\r\n    .long   0                           /* Reserved */\r\n    .long   0                           /* Reserved */\r\n    .long   SVC_Handler                 /* SVCall Handler */\r\n    .long   0                           /* Reserved */\r\n    .long   0                           /* Reserved */\r\n    .long   PendSV_Handler              /* PendSV Handler */\r\n    .long   SysTick_Handler             /* SysTick Handler */\r\n\r\n  /* External Interrupts */\r\n    .long   POWER_CLOCK_IRQHandler\r\n    .long   RADIO_IRQHandler\r\n    .long   UARTE0_UART0_IRQHandler\r\n    .long   SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0_IRQHandler\r\n    .long   SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1_IRQHandler\r\n    .long   NFCT_IRQHandler\r\n    .long   GPIOTE_IRQHandler\r\n    .long   SAADC_IRQHandler\r\n    .long   TIMER0_IRQHandler\r\n    .long   TIMER1_IRQHandler\r\n    .long   TIMER2_IRQHandler\r\n    .long   RTC0_IRQHandler\r\n    .long   TEMP_IRQHandler\r\n    .long   RNG_IRQHandler\r\n    .long   ECB_IRQHandler\r\n    .long   CCM_AAR_IRQHandler\r\n    .long   WDT_IRQHandler\r\n    .long   RTC1_IRQHandler\r\n    .long   QDEC_IRQHandler\r\n    .long   COMP_LPCOMP_IRQHandler\r\n    .long   SWI0_EGU0_IRQHandler\r\n    .long   SWI1_EGU1_IRQHandler\r\n    .long   SWI2_EGU2_IRQHandler\r\n    .long   SWI3_EGU3_IRQHandler\r\n    .long   SWI4_EGU4_IRQHandler\r\n    .long   SWI5_EGU5_IRQHandler\r\n    .long   TIMER3_IRQHandler\r\n    .long   TIMER4_IRQHandler\r\n    .long   PWM0_IRQHandler\r\n    .long   PDM_IRQHandler\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   MWU_IRQHandler\r\n    .long   PWM1_IRQHandler\r\n    .long   PWM2_IRQHandler\r\n    .long   SPIM2_SPIS2_SPI2_IRQHandler\r\n    .long   RTC2_IRQHandler\r\n    .long   I2S_IRQHandler\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n    .long   0                         /*Reserved */\r\n\r\n    .size    __Vectors, . - __Vectors\r\n\r\n/* Reset Handler */\r\n\r\n    .text\r\n    .thumb\r\n    .thumb_func\r\n    .align 1\r\n    .globl    Reset_Handler\r\n    .type    Reset_Handler, %function\r\nReset_Handler:\r\n    .fnstart\r\n\r\n\r\n/*     Loop to copy data from read only memory to RAM. The ranges\r\n *      of copy from/to are specified by following symbols evaluated in \r\n *      linker script.\r\n *      __etext: End of code section, i.e., begin of data sections to copy from.\r\n *      __data_start__/__data_end__: RAM address range that data should be\r\n *      copied to. Both must be aligned to 4 bytes boundary.  */\r\n\r\n    ldr    r1, =__etext\r\n    ldr    r2, =__data_start__\r\n    ldr    r3, =__data_end__\r\n\r\n    subs    r3, r2\r\n    ble     .LC0\r\n\r\n.LC1:\r\n    subs    r3, 4\r\n    ldr    r0, [r1,r3]\r\n    str    r0, [r2,r3]\r\n    bgt    .LC1\r\n.LC0:\r\n    \r\n    LDR     R0, =SystemInit\r\n    BLX     R0\r\n    LDR     R0, =_start\r\n    BX      R0\r\n\r\n    .pool\r\n    .cantunwind\r\n    .fnend\r\n    .size   Reset_Handler,.-Reset_Handler\r\n\r\n    .section \".text\"\r\n\r\n\r\n/* Dummy Exception Handlers (infinite loops which can be modified) */\r\n\r\n    .weak   NMI_Handler\r\n    .type   NMI_Handler, %function\r\nNMI_Handler:\r\n    B       .\r\n    .size   NMI_Handler, . - NMI_Handler\r\n\r\n\r\n    .weak   HardFault_Handler\r\n    .type   HardFault_Handler, %function\r\nHardFault_Handler:\r\n    B       .\r\n    .size   HardFault_Handler, . - HardFault_Handler\r\n\r\n\r\n    .weak   MemoryManagement_Handler\r\n    .type   MemoryManagement_Handler, %function\r\nMemoryManagement_Handler:\r\n    B       .\r\n    .size   MemoryManagement_Handler, . - MemoryManagement_Handler\r\n\r\n\r\n    .weak   BusFault_Handler\r\n    .type   BusFault_Handler, %function\r\nBusFault_Handler:\r\n    B       .\r\n    .size   BusFault_Handler, . - BusFault_Handler\r\n\r\n\r\n    .weak   UsageFault_Handler\r\n    .type   UsageFault_Handler, %function\r\nUsageFault_Handler:\r\n    B       .\r\n    .size   UsageFault_Handler, . - UsageFault_Handler\r\n\r\n\r\n    .weak   SVC_Handler\r\n    .type   SVC_Handler, %function\r\nSVC_Handler:\r\n    B       .\r\n    .size   SVC_Handler, . - SVC_Handler\r\n\r\n\r\n    .weak   PendSV_Handler\r\n    .type   PendSV_Handler, %function\r\nPendSV_Handler:\r\n    B       .\r\n    .size   PendSV_Handler, . - PendSV_Handler\r\n\r\n\r\n    .weak   SysTick_Handler\r\n    .type   SysTick_Handler, %function\r\nSysTick_Handler:\r\n    B       .\r\n    .size   SysTick_Handler, . - SysTick_Handler\r\n\r\n\r\n/* IRQ Handlers */\r\n\r\n    .globl  Default_Handler\r\n    .type   Default_Handler, %function\r\nDefault_Handler:\r\n    B       .\r\n    .size   Default_Handler, . - Default_Handler\r\n\r\n    .macro  IRQ handler\r\n    .weak   \\handler\r\n    .set    \\handler, Default_Handler\r\n    .endm\r\n\r\n    IRQ  POWER_CLOCK_IRQHandler\r\n    IRQ  RADIO_IRQHandler\r\n    IRQ  UARTE0_UART0_IRQHandler\r\n    IRQ  SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0_IRQHandler\r\n    IRQ  SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1_IRQHandler\r\n    IRQ  NFCT_IRQHandler\r\n    IRQ  GPIOTE_IRQHandler\r\n    IRQ  SAADC_IRQHandler\r\n    IRQ  TIMER0_IRQHandler\r\n    IRQ  TIMER1_IRQHandler\r\n    IRQ  TIMER2_IRQHandler\r\n    IRQ  RTC0_IRQHandler\r\n    IRQ  TEMP_IRQHandler\r\n    IRQ  RNG_IRQHandler\r\n    IRQ  ECB_IRQHandler\r\n    IRQ  CCM_AAR_IRQHandler\r\n    IRQ  WDT_IRQHandler\r\n    IRQ  RTC1_IRQHandler\r\n    IRQ  QDEC_IRQHandler\r\n    IRQ  COMP_LPCOMP_IRQHandler\r\n    IRQ  SWI0_EGU0_IRQHandler\r\n    IRQ  SWI1_EGU1_IRQHandler\r\n    IRQ  SWI2_EGU2_IRQHandler\r\n    IRQ  SWI3_EGU3_IRQHandler\r\n    IRQ  SWI4_EGU4_IRQHandler\r\n    IRQ  SWI5_EGU5_IRQHandler\r\n    IRQ  TIMER3_IRQHandler\r\n    IRQ  TIMER4_IRQHandler\r\n    IRQ  PWM0_IRQHandler\r\n    IRQ  PDM_IRQHandler\r\n    IRQ  MWU_IRQHandler\r\n    IRQ  PWM1_IRQHandler\r\n    IRQ  PWM2_IRQHandler\r\n    IRQ  SPIM2_SPIS2_SPI2_IRQHandler\r\n    IRQ  RTC2_IRQHandler\r\n    IRQ  I2S_IRQHandler\r\n\r\n  .end\r\n"
  },
  {
    "path": "examples/nrf52_toolchain_support/nrf52.ld",
    "content": "/* Linker script to configure memory regions. */\r\n\r\nGROUP(-lgcc -lc -lnosys)\r\n\r\nMEMORY\r\n{\r\n  FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 256K\r\n  RAM (rwx) :  ORIGIN = 0x20000000, LENGTH = 32K\r\n}\r\n\r\n#include \"gcc_nrf5x_common.ld\"\r\n"
  },
  {
    "path": "examples/nrf52_toolchain_support/platform.cmake",
    "content": "if(CMAKE_CROSSCOMPILING)\n    # set global compile options that depend on hardware and must apply to\n    # all targets of the project\n    add_compile_options(-mcpu=cortex-m4 -mthumb -mabi=aapcs -mfloat-abi=soft)\n    # when cmake's 3.13 is released we'll replace this with add_linker_options()\n    set(CMAKE_EXE_LINKER_FLAGS \"${CMAKE_EXE_LINKER_FLAGS} -mcpu=cortex-m4 -mthumb -mabi=aapcs -mfloat-abi=soft\")\nelse()\n    message(error \"\")\nendif()\n"
  },
  {
    "path": "examples/nrf52_toolchain_support/system_nrf52.c",
    "content": "/* Copyright (c) 2015, Nordic Semiconductor ASA\r\n * All rights reserved.\r\n *\r\n * Redistribution and use in source and binary forms, with or without\r\n * modification, are permitted provided that the following conditions are met:\r\n *\r\n *   * Redistributions of source code must retain the above copyright notice, this\r\n *     list of conditions and the following disclaimer.\r\n *\r\n *   * Redistributions in binary form must reproduce the above copyright notice,\r\n *     this list of conditions and the following disclaimer in the documentation\r\n *     and/or other materials provided with the distribution.\r\n *\r\n *   * Neither the name of Nordic Semiconductor ASA nor the names of its\r\n *     contributors may be used to endorse or promote products derived from\r\n *     this software without specific prior written permission.\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\r\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\r\n * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\r\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\r\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\r\n * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\r\n * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\r\n * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\r\n * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r\n *\r\n */\r\n\r\n#include <stdint.h>\r\n#include <stdbool.h>\r\n#include \"nrf.h\"\r\n#include \"system_nrf52.h\"\r\n\r\n/*lint ++flb \"Enter library region\" */\r\n\r\n#define __SYSTEM_CLOCK_16M      (16000000UL)     \r\n#define __SYSTEM_CLOCK_64M      (64000000UL)   \r\n\r\nstatic bool ftpan_32(void); \r\nstatic bool ftpan_37(void); \r\nstatic bool ftpan_36(void); \r\n\r\n\r\n#if defined ( __CC_ARM )\r\n    uint32_t SystemCoreClock __attribute__((used)) = __SYSTEM_CLOCK_64M;\r\n#elif defined ( __ICCARM__ )\r\n    __root uint32_t SystemCoreClock = __SYSTEM_CLOCK_64M;\r\n#elif defined   ( __GNUC__ )\r\n    uint32_t SystemCoreClock __attribute__((used)) = __SYSTEM_CLOCK_64M;\r\n#endif\r\n\r\nvoid SystemCoreClockUpdate(void)\r\n{\r\n    SystemCoreClock = __SYSTEM_CLOCK_64M;\r\n}\r\n\r\nvoid SystemInit(void)\r\n{\r\n    /* Workaround for FTPAN-32 \"DIF: Debug session automatically enables TracePort pins\" found at Product Anomaly document \r\n       for your device located at https://www.nordicsemi.com/ */\r\n    if (ftpan_32()){        \r\n        CoreDebug->DEMCR &= ~CoreDebug_DEMCR_TRCENA_Msk;\r\n    }\r\n    \r\n    /* Workaround for FTPAN-37 \"AMLI: EasyDMA is slow with Radio, ECB, AAR and CCM.\" found at Product Anomaly document \r\n       for your device located at https://www.nordicsemi.com/  */\r\n    if (ftpan_37()){        \r\n        *(volatile uint32_t *)0x400005A0 = 0x3;\r\n    }\r\n    \r\n    /* Workaround for FTPAN-36 \"CLOCK: Some registers are not reset when expected.\" found at Product Anomaly document \r\n       for your device located at https://www.nordicsemi.com/  */\r\n    if (ftpan_36()){        \r\n        NRF_CLOCK->EVENTS_DONE = 0;\r\n        NRF_CLOCK->EVENTS_CTTO = 0;\r\n    }\r\n\r\n    /* Enable the FPU if the compiler used floating point unit instructions. __FPU_USED is a MACRO defined by the \r\n     * compiler. Since the FPU consumes energy, remember to disable FPU use in the compiler if floating point unit \r\n     * operations are not used in your code. */\r\n    #if (__FPU_USED == 1)\r\n        SCB->CPACR |= (3UL << 20) | (3UL << 22); \r\n        __DSB();\r\n        __ISB();\r\n    #endif\r\n    \r\n    /* Configure NFCT pins as GPIOs if NFCT is not to be used in your code. If CONFIG_NFCT_PINS_AS_GPIOS is not defined, \r\n       two GPIOs (see Product Specification to see which ones) will be reserved for NFC and will not be available as \r\n       normal GPIOs. */\r\n    #if defined (CONFIG_NFCT_PINS_AS_GPIOS)\r\n        if ((NRF_UICR->NFCPINS & UICR_NFCPINS_PROTECT_Msk) == (UICR_NFCPINS_PROTECT_NFC << UICR_NFCPINS_PROTECT_Pos)){\r\n            NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Wen << NVMC_CONFIG_WEN_Pos;\r\n            while (NRF_NVMC->READY == NVMC_READY_READY_Busy){}            \r\n            NRF_UICR->NFCPINS &= ~UICR_NFCPINS_PROTECT_Msk;\r\n            while (NRF_NVMC->READY == NVMC_READY_READY_Busy){}            \r\n            NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Ren << NVMC_CONFIG_WEN_Pos;\r\n            while (NRF_NVMC->READY == NVMC_READY_READY_Busy){}            \r\n            NVIC_SystemReset();\r\n        }\r\n    #endif\r\n    \r\n    /* Configure GPIO pads as pPin Reset pin if Pin Reset capabilities desired. If CONFIG_GPIO_AS_PINRESET is not\r\n      defined, pin reset will not be available. One GPIO (see Product Specification to see which one) will then be \r\n      reserved for PinReset and not available as normal GPIO. */\r\n    #if defined (CONFIG_GPIO_AS_PINRESET)\r\n        if (((NRF_UICR->PSELRESET[0] & UICR_PSELRESET_CONNECT_Msk) != (UICR_PSELRESET_CONNECT_Connected << UICR_PSELRESET_CONNECT_Pos)) || \r\n            ((NRF_UICR->PSELRESET[0] & UICR_PSELRESET_CONNECT_Msk) != (UICR_PSELRESET_CONNECT_Connected << UICR_PSELRESET_CONNECT_Pos))){\r\n            NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Wen << NVMC_CONFIG_WEN_Pos;\r\n            while (NRF_NVMC->READY == NVMC_READY_READY_Busy){}\r\n            NRF_UICR->PSELRESET[0] = 21;\r\n            while (NRF_NVMC->READY == NVMC_READY_READY_Busy){}\r\n            NRF_UICR->PSELRESET[1] = 21;\r\n            while (NRF_NVMC->READY == NVMC_READY_READY_Busy){}\r\n            NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Ren << NVMC_CONFIG_WEN_Pos;\r\n            while (NRF_NVMC->READY == NVMC_READY_READY_Busy){}\r\n            NVIC_SystemReset();\r\n        }\r\n    #endif\r\n    \r\n    /* Enable SWO trace functionality. If ENABLE_SWO is not defined, SWO pin will be used as GPIO (see Product \r\n       Specification to see which one). */\r\n    #if defined (ENABLE_SWO)\r\n        CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;\r\n        NRF_CLOCK->TRACECONFIG |= CLOCK_TRACECONFIG_TRACEMUX_Serial << CLOCK_TRACECONFIG_TRACEMUX_Pos;\r\n    #endif\r\n    \r\n    /* Enable Trace functionality. If ENABLE_TRACE is not defined, TRACE pins will be used as GPIOs (see Product \r\n       Specification to see which ones). */\r\n    #if defined (ENABLE_TRACE)\r\n        CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;\r\n        NRF_CLOCK->TRACECONFIG |= CLOCK_TRACECONFIG_TRACEMUX_Parallel << CLOCK_TRACECONFIG_TRACEMUX_Pos;\r\n    #endif\r\n\r\n    SystemCoreClockUpdate();\r\n}\r\n\r\nstatic bool ftpan_32(void)\r\n{\r\n    if ((((*(uint32_t *)0xF0000FE0) & 0x000000FF) == 0x6) && (((*(uint32_t *)0xF0000FE4) & 0x0000000F) == 0x0))\r\n    {\r\n        if ((((*(uint32_t *)0xF0000FE8) & 0x000000F0) == 0x30) && (((*(uint32_t *)0xF0000FEC) & 0x000000F0) == 0x0))\r\n        {\r\n            return true;\r\n        }\r\n    }\r\n    \r\n    return false;\r\n}\r\n\r\nstatic bool ftpan_37(void)\r\n{\r\n    if ((((*(uint32_t *)0xF0000FE0) & 0x000000FF) == 0x6) && (((*(uint32_t *)0xF0000FE4) & 0x0000000F) == 0x0))\r\n    {\r\n        if ((((*(uint32_t *)0xF0000FE8) & 0x000000F0) == 0x30) && (((*(uint32_t *)0xF0000FEC) & 0x000000F0) == 0x0))\r\n        {\r\n            return true;\r\n        }\r\n    }\r\n    \r\n    return false;\r\n}\r\n\r\nstatic bool ftpan_36(void)\r\n{\r\n    if ((((*(uint32_t *)0xF0000FE0) & 0x000000FF) == 0x6) && (((*(uint32_t *)0xF0000FE4) & 0x0000000F) == 0x0))\r\n    {\r\n        if ((((*(uint32_t *)0xF0000FE8) & 0x000000F0) == 0x30) && (((*(uint32_t *)0xF0000FEC) & 0x000000F0) == 0x0))\r\n        {\r\n            return true;\r\n        }\r\n    }\r\n    \r\n    return false;\r\n}\r\n\r\n\r\n\r\n/*lint --flb \"Leave library region\" */\r\n"
  },
  {
    "path": "examples/nrf52_toolchain_support/system_nrf52.h",
    "content": "/* Copyright (c) 2015, Nordic Semiconductor ASA\r\n * All rights reserved.\r\n *\r\n * Redistribution and use in source and binary forms, with or without\r\n * modification, are permitted provided that the following conditions are met:\r\n *\r\n *   * Redistributions of source code must retain the above copyright notice, this\r\n *     list of conditions and the following disclaimer.\r\n *\r\n *   * Redistributions in binary form must reproduce the above copyright notice,\r\n *     this list of conditions and the following disclaimer in the documentation\r\n *     and/or other materials provided with the distribution.\r\n *\r\n *   * Neither the name of Nordic Semiconductor ASA nor the names of its\r\n *     contributors may be used to endorse or promote products derived from\r\n *     this software without specific prior written permission.\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\r\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\r\n * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\r\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\r\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\r\n * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\r\n * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\r\n * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\r\n * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r\n *\r\n */\r\n\r\n#ifndef SYSTEM_NRF52_H\r\n#define SYSTEM_NRF52_H\r\n\r\n#ifdef __cplusplus\r\nextern \"C\" {\r\n#endif\r\n\r\n#include <stdint.h>\r\n\r\n\r\nextern uint32_t SystemCoreClock;    /*!< System Clock Frequency (Core Clock)  */\r\n\r\n/**\r\n * Initialize the system\r\n *\r\n * @param  none\r\n * @return none\r\n *\r\n * @brief  Setup the microcontroller system.\r\n *         Initialize the System and update the SystemCoreClock variable.\r\n */\r\nextern void SystemInit (void);\r\n\r\n/**\r\n * Update SystemCoreClock variable\r\n *\r\n * @param  none\r\n * @return none\r\n *\r\n * @brief  Updates the SystemCoreClock with current core Clock \r\n *         retrieved from cpu registers.\r\n */\r\nextern void SystemCoreClockUpdate (void);\r\n\r\n#ifdef __cplusplus\r\n}\r\n#endif\r\n\r\n#endif /* SYSTEM_NRF52_H */\r\n"
  },
  {
    "path": "examples/resources.hpp",
    "content": "#ifndef BLUETOE_EXAMPLES_RESOURCES_HPP\n#define BLUETOE_EXAMPLES_RESOURCES_HPP\n\n#include <spl/gpio.hpp>\n#include <spl/temperature.hpp>\n\nnamespace examples {\n\n    template < std::uint32_t Pin >\n    using nordic_output = spl::output_pin<\n        spl::pin_p0< Pin >,\n        spl::inverted_output\n    >;\n\n    template < std::uint32_t Pin >\n    using nordic_input = spl::input_pin<\n        spl::pin_p0< Pin >,\n        spl::inverted_input,\n        spl::enable_pullup\n    >;\n\n#if defined BLUETOE_BOARD_PCA10056\n\n    using led1    = nordic_output < 13 >;\n    using led2    = nordic_output < 14 >;\n    using led3    = nordic_output < 15 >;\n    using led4    = nordic_output < 16 >;\n    using button1 = nordic_input< 11 >;\n    using button2 = nordic_input< 12 >;\n    using button3 = nordic_input< 24 >;\n    using button4 = nordic_input< 25 >;\n\n#elif defined BLUETOE_BOARD_PCA10040\n\n    using led1    = nordic_output < 17 >;\n    using led2    = nordic_output < 18 >;\n    using led3    = nordic_output < 19 >;\n    using led4    = nordic_output < 20 >;\n    using button1 = nordic_input< 13 >;\n    using button2 = nordic_input< 14 >;\n    using button3 = nordic_input< 15 >;\n    using button4 = nordic_input< 16 >;\n\n#else\n\n    using led1    = nordic_output < 13 >;\n    using led2    = nordic_output < 14 >;\n    using led3    = nordic_output < 15 >;\n    using led4    = nordic_output < 16 >;\n    using button1 = nordic_input< 11 >;\n    using button2 = nordic_input< 12 >;\n    using button3 = nordic_input< 24 >;\n    using button4 = nordic_input< 25 >;\n\n#endif\n\n    using led    = led1;\n    using button = button1;\n    using temperature = spl::temperature<>;\n\n} // namespace examples\n\n#endif\n"
  },
  {
    "path": "examples/runtime_gcc.cpp",
    "content": "#include <cstdint>\n\nextern \"C\" void __cxa_pure_virtual(void) {}\n\nextern \"C\" void (*__preinit_array_start []) (void) __attribute__((weak));\nextern \"C\" void (*__preinit_array_end []) (void) __attribute__((weak));\nextern \"C\" void (*__init_array_start []) (void) __attribute__((weak));\nextern \"C\" void (*__init_array_end []) (void) __attribute__((weak));\nextern \"C\" void (*__fini_array_start []) (void) __attribute__((weak));\nextern \"C\" void (*__fini_array_end []) (void) __attribute__((weak));\n\nextern \"C\" typedef void (*vector)();\n\nextern \"C\" std::uint32_t __bss_start__;\nextern \"C\" std::uint32_t __bss_end__;\n\nextern \"C\" void _start(void) {\n    extern int main(void);\n\n    // zero initialize static allocated variables\n    for ( std::uint32_t* bss = &__bss_start__; bss != &__bss_end__; ++bss )\n        *bss = 0;\n\n    for ( vector* init = &__preinit_array_start[ 0 ]; init != &__preinit_array_end[ 0 ]; ++init )\n        (*init)();\n\n    for ( vector* init = &__init_array_start[ 0 ]; init != &__init_array_end[ 0 ]; ++init )\n        (*init)();\n\n#pragma GCC diagnostic push\n#pragma GCC diagnostic ignored \"-Wpedantic\"\n// ISO C++ forbids calling main. We are silencing this warning explicitly.\n// This startup code replaces the one provided by newlib, which is not being used in\n// order to save space from the final binary.\n    main();\n#pragma GCC diagnostic pop\n\n    for ( vector* finit = &__fini_array_start[ 0 ]; finit != &__fini_array_end[ 0 ]; ++finit )\n        (*finit)();\n\n}\n"
  },
  {
    "path": "examples/scheduled_radio_tests.cpp",
    "content": "#include <bluetoe/nrf51.hpp>\n#include <cassert>\n#include <algorithm>\n#include <functional>\n\nstruct radio_t : bluetoe::nrf51_details::scheduled_radio_factory<\n            bluetoe::nrf51_details::scheduled_radio_base_with_encryption<>\n        >::template scheduled_radio< 100, 100, radio_t >\n{\n    void adv_received( const bluetoe::link_layer::read_buffer& )\n    {\n    }\n\n    bool is_scan_request_in_filter( const bluetoe::link_layer::device_address& ) const\n    {\n        return true;\n    }\n};\n\nstatic bool c1_test()\n{\n    const bluetoe::details::uint128_t p1{{\n        0x01, 0x00, 0x01, 0x01,\n        0x00, 0x00, 0x10, 0x07,\n        0x07, 0x02, 0x03, 0x00,\n        0x00, 0x08, 0x00, 0x05\n    }};\n\n    const bluetoe::details::uint128_t p2{{\n        0xB6, 0xB5, 0xB4, 0xB3,\n        0xB2, 0xB1, 0xA6, 0xA5,\n        0xA4, 0xA3, 0xA2, 0xA1,\n        0x00, 0x00, 0x00, 0x00\n    }};\n\n    const bluetoe::details::uint128_t k{{\n        0x00, 0x00, 0x00, 0x00,\n        0x00, 0x00, 0x00, 0x00,\n        0x00, 0x00, 0x00, 0x00,\n        0x00, 0x00, 0x00, 0x00\n    }};\n\n    const bluetoe::details::uint128_t r{{\n        0xE0, 0x2E, 0x70, 0xC6,\n        0x4E, 0x27, 0x88, 0x63,\n        0x0E, 0x6F, 0xAD, 0x56,\n        0x21, 0xD5, 0x83, 0x57\n    }};\n\n    const bluetoe::details::uint128_t expected{{\n        0x86, 0x3b, 0xf1, 0xbe,\n        0xc5, 0x4d, 0xa7, 0xd2,\n        0xea, 0x88, 0x89, 0x87,\n        0xef, 0x3f, 0x1e, 0x1e\n    }};\n\n    radio_t radio;\n    const bluetoe::details::uint128_t confirm = radio.c1( k, r, p1, p2 );\n\n    return std::distance( confirm.begin(), confirm.end() ) == std::distance( expected.begin(), expected.end() )\n        && std::equal( confirm.begin(), confirm.end(), expected.begin() );\n}\n\nstatic bool s1_test()\n{\n    static const bluetoe::details::uint128_t k = {\n        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00\n    };\n\n    // r1 = 0x000F0E0D0C0B0A091122334455667788\n    static const bluetoe::details::uint128_t r1 = {\n        0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11,\n        0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x00\n    };\n\n    // r2 = 0x010203040506070899AABBCCDDEEFF00\n    static const bluetoe::details::uint128_t r2 = {\n        0x00, 0xFF, 0xEE, 0xDD, 0xCC, 0xBB, 0xAA, 0x99,\n        0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01\n    };\n\n    // 0x9a1fe1f0e8b0f49b5b4216ae796da062\n    static const bluetoe::details::uint128_t expected = {\n        0x62, 0xa0, 0x6d, 0x79, 0xae, 0x16, 0x42, 0x5b,\n        0x9b, 0xf4, 0xb0, 0xe8, 0xf0, 0xe1, 0x1f, 0x9a\n    };\n\n    radio_t radio;\n\n    const bluetoe::details::uint128_t key = radio.s1( k, r1, r2 );\n\n    return std::distance( key.begin(), key.end() ) == std::distance( expected.begin(), expected.end() )\n        && std::equal( key.begin(), key.end(), expected.begin() );\n}\n\n/*\n * This test does not have a easily oberservable result, but can be used for debugging.\n\n\nLTK = 0x4C68384139F574D836BCF34E9DFB01BF (MSO to LSO)\nEDIV = 0x2474 (MSO to LSO)\nRAND = 0xABCDEF1234567890 (MSO to LSO)\nSKDm = 0xACBDCEDFE0F10213 (MSO to LSO)\nSKDs = 0x0213243546576879 (MSO to LSO)\nIVm = 0xBADCAB24 (MSO to LSO)\nIVs = 0xDEAFBABE (MSO to LSO)\n\n */\nstatic bool setup_encryption_test()\n{\n    static const std::uint64_t SKDm = 0xACBDCEDFE0F10213;\n    static const std::uint32_t IVm  = 0xBADCAB24;\n\n    static const bluetoe::details::uint128_t key = {\n\n        0xBF, 0x01, 0xFB, 0x9D, 0x4E, 0xF3, 0xBC, 0x36,\n        0xD8, 0x74, 0xF5, 0x39, 0x41, 0x38, 0x68, 0x4C\n    };\n\n    radio_t radio;\n    std::pair< std::uint64_t, std::uint32_t > r = radio.setup_encryption( key, SKDm, IVm );\n\n    static_cast< void >( r );\n\n    return true;\n}\n\nstatic bool is_valid_public_key_test()\n{\n    static const bluetoe::details::ecdh_public_key_t valid_key = {{\n        // Public Key X\n        0xe6, 0x9d, 0x35, 0x0e,\n        0x48, 0x01, 0x03, 0xcc,\n        0xdb, 0xfd, 0xf4, 0xac,\n        0x11, 0x91, 0xf4, 0xef,\n        0xb9, 0xa5, 0xf9, 0xe9,\n        0xa7, 0x83, 0x2c, 0x5e,\n        0x2c, 0xbe, 0x97, 0xf2,\n        0xd2, 0x03, 0xb0, 0x20,\n        // Public Key Y\n        0x8b, 0xd2, 0x89, 0x15,\n        0xd0, 0x8e, 0x1c, 0x74,\n        0x24, 0x30, 0xed, 0x8f,\n        0xc2, 0x45, 0x63, 0x76,\n        0x5c, 0x15, 0x52, 0x5a,\n        0xbf, 0x9a, 0x32, 0x63,\n        0x6d, 0xeb, 0x2a, 0x65,\n        0x49, 0x9c, 0x80, 0xdc\n    }};\n\n    static const bluetoe::details::ecdh_public_key_t invalid_key = {{\n        0xe6, 0x9d, 0x35, 0x0e,\n        0x48, 0x01, 0x03, 0xcc,\n        0xdb, 0xfd, 0xf4, 0xac,\n        0x11, 0x91, 0xf4, 0xef,\n        0xb9, 0xa5, 0xf9, 0xe9,\n        0xa7, 0x83, 0x2c, 0x5e,\n        0x2c, 0xbe, 0x97, 0xf2,\n        0xd2, 0x03, 0xb0, 0x20,\n        // Public Key Y\n        0x8b, 0xd2, 0x89, 0x15,\n        0xd0, 0x8e, 0x1c, 0x74,\n        0x24, 0x30, 0xed, 0x8f,\n        0xc2, 0x45, 0x63, 0x76,\n        0x5c, 0x15, 0x52, 0x5a,\n        0xbf, 0x9a, 0x32, 0x63,\n        0x6d, 0xeb, 0x2a, 0x65,\n        0x49, 0x9c, 0x80, 0x00\n    }};\n\n    radio_t radio;\n\n    return radio.is_valid_public_key( valid_key.data() ) && !radio.is_valid_public_key( invalid_key.data() );\n}\n\ntemplate < class K >\nstatic bool find_key_duplicate( const K* begin, const K* end )\n{\n    if ( begin == end )\n        return false;\n\n    const K& key = *begin;\n    ++begin;\n\n    for ( ; begin != end; ++begin )\n    {\n        if ( std::equal( key.first.begin(), key.first.end(), begin->first.begin() )\n          or std::equal( key.second.begin(), key.second.end(), begin->second.begin() ) )\n            return true;\n    }\n\n    return false;\n}\n\ntemplate < class KP >\nstatic bool try_create_shared_secret( radio_t& radion, const KP& first_pair, const KP& second_pair )\n{\n    const bluetoe::details::ecdh_shared_secret_t shared1 = radion.p256( first_pair.second.data(), second_pair.first.data() );\n    const bluetoe::details::ecdh_shared_secret_t shared2 = radion.p256( second_pair.second.data(), first_pair.first.data() );\n\n    return std::equal( shared1.begin(), shared1.end(), shared2.begin() );\n}\n\nstatic bool generate_keys_test()\n{\n    static constexpr std::size_t num_keys = 10;\n    std::pair< bluetoe::details::ecdh_public_key_t, bluetoe::details::ecdh_private_key_t > keys[ num_keys ];\n\n    radio_t radio;\n    std::generate( std::begin( keys ), std::end( keys ), [&]() -> std::pair< bluetoe::details::ecdh_public_key_t, bluetoe::details::ecdh_private_key_t >\n    {\n        return radio.generate_keys();\n    });\n\n    // make sure, all keys are different\n    for ( int key_idx = 0; key_idx != num_keys; ++key_idx )\n    {\n        if ( find_key_duplicate( std::next( std::begin( keys ), key_idx ), std::end( keys ) ) )\n            return false;\n    }\n\n    // make sure, all public keys are valid\n    for ( const auto& key : keys )\n    {\n        if ( !radio.is_valid_public_key( key.first.data() ) )\n            return false;\n    }\n\n    // use keys pairwise to generate and compare a shared secret\n    static_assert( ( num_keys & 1 )  == 0, \"number of key must be odd for this tests\" );\n    for ( int key_idx = 0; key_idx != num_keys; key_idx += 2 )\n    {\n        if ( !try_create_shared_secret( radio, keys[ key_idx ], keys[ key_idx + 1 ] ) )\n            return false;\n    }\n\n    return true;\n}\n\nstatic bool p256_test()\n{\n    const bluetoe::details::ecdh_private_key_t Private_A = {{\n        0xbd, 0x1a, 0x3c, 0xcd, 0xa6, 0xb8, 0x99, 0x58,\n        0x99, 0xb7, 0x40, 0xeb, 0x7b, 0x60, 0xff, 0x4a,\n        0x50, 0x3f, 0x10, 0xd2, 0xe3, 0xb3, 0xc9, 0x74,\n        0x38, 0x5f, 0xc5, 0xa3, 0xd4, 0xf6, 0x49, 0x3f\n    }};\n\n    const bluetoe::details::ecdh_private_key_t Private_B = {{\n        0xfd, 0xc5, 0x7f, 0xf4, 0x49, 0xdd, 0x4f, 0x6b,\n        0xfb, 0x7c, 0x9d, 0xf1, 0xc2, 0x9a, 0xcb, 0x59,\n        0x2a, 0xe7, 0xd4, 0xee, 0xfb, 0xfc, 0x0a, 0x90,\n        0x9a, 0xbb, 0xf6, 0x32, 0x3d, 0x8b, 0x18, 0x55\n    }};\n\n    const bluetoe::details::ecdh_public_key_t Public_A = {{\n        0xe6, 0x9d, 0x35, 0x0e, 0x48, 0x01, 0x03, 0xcc,\n        0xdb, 0xfd, 0xf4, 0xac, 0x11, 0x91, 0xf4, 0xef,\n        0xb9, 0xa5, 0xf9, 0xe9, 0xa7, 0x83, 0x2c, 0x5e,\n        0x2c, 0xbe, 0x97, 0xf2, 0xd2, 0x03, 0xb0, 0x20,\n\n        0x8b, 0xd2, 0x89, 0x15, 0xd0, 0x8e, 0x1c, 0x74,\n        0x24, 0x30, 0xed, 0x8f, 0xc2, 0x45, 0x63, 0x76,\n        0x5c, 0x15, 0x52, 0x5a, 0xbf, 0x9a, 0x32, 0x63,\n        0x6d, 0xeb, 0x2a, 0x65, 0x49, 0x9c, 0x80, 0xdc\n    }};\n\n    const bluetoe::details::ecdh_public_key_t Public_B = {{\n        0x90, 0xa1, 0xaa, 0x2f, 0xb2, 0x77, 0x90, 0x55,\n        0x9f, 0xa6, 0x15, 0x86, 0xfd, 0x8a, 0xb5, 0x47,\n        0x00, 0x4c, 0x9e, 0xf1, 0x84, 0x22, 0x59, 0x09,\n        0x96, 0x1d, 0xaf, 0x1f, 0xf0, 0xf0, 0xa1, 0x1e,\n\n        0x4a, 0x21, 0xb1, 0x15, 0xf9, 0xaf, 0x89, 0x5f,\n        0x76, 0x36, 0x8e, 0xe2, 0x30, 0x11, 0x2d, 0x47,\n        0x60, 0x51, 0xb8, 0x9a, 0x3a, 0x70, 0x56, 0x73,\n        0x37, 0xad, 0x9d, 0x42, 0x3e, 0xf3, 0x55, 0x4c\n    }};\n\n    const bluetoe::details::ecdh_shared_secret_t DHKey = {{\n        0x98, 0xa6, 0xbf, 0x73, 0xf3, 0x34, 0x8d, 0x86,\n        0xf1, 0x66, 0xf8, 0xb4, 0x13, 0x6b, 0x79, 0x99,\n        0x9b, 0x7d, 0x39, 0x0a, 0xa6, 0x10, 0x10, 0x34,\n        0x05, 0xad, 0xc8, 0x57, 0xa3, 0x34, 0x02, 0xec\n    }};\n\n    radio_t radio;\n\n    const auto shared_a = radio.p256( Private_A.data(), Public_B.data() );\n    const auto shared_b = radio.p256( Private_B.data(), Public_A.data() );\n\n    return std::equal( DHKey.begin(), DHKey.end(), shared_a.begin(), shared_a.end() )\n        && std::equal( DHKey.begin(), DHKey.end(), shared_b.begin(), shared_b.end() );\n\n}\n\nstatic bool f4_test()\n{\n    const std::array< std::uint8_t, 32 > u = {{\n        0xe6, 0x9d, 0x35, 0x0e,\n        0x48, 0x01, 0x03, 0xcc,\n        0xdb, 0xfd, 0xf4, 0xac,\n        0x11, 0x91, 0xf4, 0xef,\n        0xb9, 0xa5, 0xf9, 0xe9,\n        0xa7, 0x83, 0x2c, 0x5e,\n        0x2c, 0xbe, 0x97, 0xf2,\n        0xd2, 0x03, 0xb0, 0x20\n    }};\n\n    const std::array< std::uint8_t, 32 > v = {{\n        0xfd, 0xc5, 0x7f, 0xf4,\n        0x49, 0xdd, 0x4f, 0x6b,\n        0xfb, 0x7c, 0x9d, 0xf1,\n        0xc2, 0x9a, 0xcb, 0x59,\n        0x2a, 0xe7, 0xd4, 0xee,\n        0xfb, 0xfc, 0x0a, 0x90,\n        0x9a, 0xbb, 0xf6, 0x32,\n        0x3d, 0x8b, 0x18, 0x55\n    }};\n\n    const bluetoe::details::uint128_t x = {{\n        0xab, 0xae, 0x2b, 0x71,\n        0xec, 0xb2, 0xff, 0xff,\n        0x3e, 0x73, 0x77, 0xd1,\n        0x54, 0x84, 0xcb, 0xd5\n    }};\n\n    const std::uint8_t z = 0x00;\n\n    const bluetoe::details::uint128_t expected{{\n        0x2d, 0x87, 0x74, 0xa9,\n        0xbe, 0xa1, 0xed, 0xf1,\n        0x1c, 0xbd, 0xa9, 0x07,\n        0xf1, 0x16, 0xc9, 0xf2\n    }};\n\n    radio_t radio;\n    const bluetoe::details::uint128_t output = radio.f4( u.data(), v.data(), x, z );\n\n    return std::equal( output.begin(), output.end(), expected.begin() );\n}\n\nstatic bool f5_test()\n{\n    const bluetoe::details::ecdh_shared_secret_t dh_key = {{\n        0x98, 0xa6, 0xbf, 0x73, 0xf3, 0x34, 0x8d, 0x86,\n        0xf1, 0x66, 0xf8, 0xb4, 0x13, 0x6b, 0x79, 0x99,\n        0x9b, 0x7d, 0x39, 0x0a, 0xa6, 0x10, 0x10, 0x34,\n        0x05, 0xad, 0xc8, 0x57, 0xa3, 0x34, 0x02, 0xec\n    }};\n\n    const bluetoe::details::uint128_t nonce_central = {{\n        0xab, 0xae, 0x2b, 0x71, 0xec, 0xb2, 0xff, 0xff,\n        0x3e, 0x73, 0x77, 0xd1, 0x54, 0x84, 0xcb, 0xd5\n    }};\n\n    const bluetoe::details::uint128_t nonce_periperal = {{\n        0xcf, 0xc4, 0x3d, 0xff, 0xf7, 0x83, 0x65, 0x21,\n        0x6e, 0x5f, 0xa7, 0x25, 0xcc, 0xe7, 0xe8, 0xa6\n    }};\n\n    const bluetoe::link_layer::public_device_address addr_controller({\n        0xce, 0xbf, 0x37, 0x37, 0x12, 0x56\n    });\n\n    const bluetoe::link_layer::public_device_address addr_peripheral({\n        0xc1, 0xcf, 0x2d, 0x70, 0x13, 0xa7\n    });\n\n    bluetoe::details::uint128_t mac_key;\n    bluetoe::details::uint128_t ltk;\n\n    radio_t radio;\n    std::tie( mac_key, ltk ) = radio.f5( dh_key, nonce_central, nonce_periperal, addr_controller, addr_peripheral );\n\n    const bluetoe::details::uint128_t expected_mac_key = {{\n        0x20, 0x6e, 0x63, 0xce, 0x20, 0x6a, 0x3f, 0xfd,\n        0x02, 0x4a, 0x08, 0xa1, 0x76, 0xf1, 0x65, 0x29\n    }};\n\n    const bluetoe::details::uint128_t expected_ltk = {{\n        0x38, 0x0a, 0x75, 0x94, 0xb5, 0x22, 0x05, 0x98,\n        0x23, 0xcd, 0xd7, 0x69, 0x11, 0x79, 0x86, 0x69\n    }};\n\n    return std::equal( mac_key.begin(), mac_key.end(), expected_mac_key.begin() )\n       and std::equal( ltk.begin(), ltk.end(), expected_ltk.begin() );\n\n}\n\nstatic bool f6_test()\n{\n    static const bluetoe::details::uint128_t nonce_central = {{\n        0xab, 0xae, 0x2b, 0x71, 0xec, 0xb2, 0xff, 0xff,\n        0x3e, 0x73, 0x77, 0xd1, 0x54, 0x84, 0xcb, 0xd5\n    }};\n\n    static const bluetoe::details::uint128_t nonce_periperal = {{\n        0xcf, 0xc4, 0x3d, 0xff, 0xf7, 0x83, 0x65, 0x21,\n        0x6e, 0x5f, 0xa7, 0x25, 0xcc, 0xe7, 0xe8, 0xa6\n    }};\n\n    static const bluetoe::details::uint128_t mac_key = {{\n        0x20, 0x6e, 0x63, 0xce, 0x20, 0x6a, 0x3f, 0xfd,\n        0x02, 0x4a, 0x08, 0xa1, 0x76, 0xf1, 0x65, 0x29\n    }};\n\n    static const bluetoe::details::uint128_t R = {{\n        0xc8, 0x0f, 0x2d, 0x0c, 0xd2, 0x42, 0xda, 0x08,\n        0x54, 0xbb, 0x53, 0xb4, 0x3b, 0x34, 0xa3, 0x12\n    }};\n\n    static const bluetoe::details::io_capabilities_t io_caps = {{\n        0x02, 0x01, 0x01\n    }};\n\n    const bluetoe::link_layer::public_device_address addr_controller({\n        0xce, 0xbf, 0x37, 0x37, 0x12, 0x56\n    });\n\n    const bluetoe::link_layer::public_device_address addr_peripheral({\n        0xc1, 0xcf, 0x2d, 0x70, 0x13, 0xa7\n    });\n\n    static const bluetoe::details::uint128_t expected_check_value = {{\n        0x61, 0x8f, 0x95, 0xda, 0x09, 0x0b, 0x6c, 0xd2,\n        0xc5, 0xe8, 0xd0, 0x9c, 0x98, 0x73, 0xc4, 0xe3\n    }};\n\n    radio_t radio;\n    const bluetoe::details::uint128_t check_value = radio.f6(\n        mac_key, nonce_central, nonce_periperal, R, io_caps, addr_controller, addr_peripheral );\n\n    return std::equal( check_value.begin(), check_value.end(), expected_check_value.begin() );\n}\n\nstatic bool try_select_random_nonce_test()\n{\n    std::uint8_t counts[ 256 ] = { 0 };\n\n    radio_t radio;\n    const auto nonce = radio.select_random_nonce();\n\n    for ( const std::uint8_t byte: nonce )\n    {\n        if ( counts[ byte ] != 0 )\n            return false;\n\n        ++counts[ byte ];\n    }\n\n    return true;\n}\n\nstatic bool select_random_nonce_test()\n{\n    bool result = try_select_random_nonce_test();\n\n    for ( int i = 0; i != 10 && !result; ++i )\n        result = try_select_random_nonce_test();\n\n    return result;\n}\n\nstatic bool g2_test()\n{\n    // D.5 g2 LE SC NUMERIC COMPARISON GENERATION FUNCTION\n    // U              20b003d2 f297be2c 5e2c83a7 e9f9a5b9\n    //                eff49111 acf4fddb cc030148 0e359de6\n    // V              55188b3d 32f6bb9a 900afcfb eed4e72a\n    //                59cb9ac2 f19d7cfb 6b4fdd49 f47fc5fd\n    // X              d5cb8454 d177733e ffffb2ec 712baeab\n    // Y              a6e8e7cc 25a75f6e 216583f7 ff3dc4cf\n    // M0             20b003d2 f297be2c 5e2c83a7 e9f9a5b9\n    // M1             eff49111 acf4fddb cc030148 0e359de6\n    // M2             55188b3d 32f6bb9a 900afcfb eed4e72a\n    // M3             59cb9ac2 f19d7cfb 6b4fdd49 f47fc5fd\n    // M4             a6e8e7cc 25a75f6e 216583f7 ff3dc4cf\n    // AES_CMAC       1536d18d e3d20df9 9b7044c1 2f9ed5ba\n    // g2             2f9ed5ba\n\n    const std::array< std::uint8_t, 32 > u = {{\n        0xe6, 0x9d, 0x35, 0x0e,\n        0x48, 0x01, 0x03, 0xcc,\n        0xdb, 0xfd, 0xf4, 0xac,\n        0x11, 0x91, 0xf4, 0xef,\n        0xb9, 0xa5, 0xf9, 0xe9,\n        0xa7, 0x83, 0x2c, 0x5e,\n        0x2c, 0xbe, 0x97, 0xf2,\n        0xd2, 0x03, 0xb0, 0x20\n    }};\n\n    const std::array< std::uint8_t, 32 > v = {{\n        0xfd, 0xc5, 0x7f, 0xf4,\n        0x49, 0xdd, 0x4f, 0x6b,\n        0xfb, 0x7c, 0x9d, 0xf1,\n        0xc2, 0x9a, 0xcb, 0x59,\n        0x2a, 0xe7, 0xd4, 0xee,\n        0xfb, 0xfc, 0x0a, 0x90,\n        0x9a, 0xbb, 0xf6, 0x32,\n        0x3d, 0x8b, 0x18, 0x55\n    }};\n\n    const bluetoe::details::uint128_t x = {{\n        0xab, 0xae, 0x2b, 0x71,\n        0xec, 0xb2, 0xff, 0xff,\n        0x3e, 0x73, 0x77, 0xd1,\n        0x54, 0x84, 0xcb, 0xd5\n    }};\n\n    const bluetoe::details::uint128_t y = {{\n        0xcf, 0xc4, 0x3d, 0xff,\n        0xf7, 0x83, 0x65, 0x21,\n        0x6e, 0x5f, 0xa7, 0x25,\n        0xcc, 0xe7, 0xe8, 0xa6\n    }};\n\n    radio_t radio;\n    return radio.g2( u.data(), v.data(), x, y ) == 0x2f9ed5bau;\n}\n\n// make it easier to set a break point here\nextern \"C\" __attribute__((optimize(\"O0\"))) void test_failed( const char* name )\n{\n    for ( ;; )\n        ;\n}\n\nextern \"C\" __attribute__((optimize(\"O0\"))) void test_success()\n{\n    for ( ;; )\n        ;\n}\n\n__attribute__((optimize(\"O0\"))) void check_result( bool result, const char* name )\n{\n    if ( !result )\n        test_failed( name );\n}\n\nint main()\n{\n    // legacy pairing\n    check_result( c1_test(), \"c1_test\" );\n    check_result( s1_test(), \"s1_test\" );\n    check_result( setup_encryption_test(), \"setup_encryption_test\" );\n\n    // lesc pairing\n    check_result( is_valid_public_key_test(), \"is_valid_public_key_test\" );\n    check_result( generate_keys_test(), \"generate_keys_test\" );\n    check_result( p256_test(), \"p256_test\" );\n    check_result( f4_test(), \"f4_test\" );\n    check_result( f5_test(), \"f5_test\" );\n    check_result( f6_test(), \"f6_test\" );\n    check_result( select_random_nonce_test(), \"select_random_nonce_test\" );\n    check_result( g2_test(), \"g2_test\" );\n\n    test_success();\n}\n"
  },
  {
    "path": "examples/spl/CMakeLists.txt",
    "content": "add_library(spl STATIC)\n\ntarget_include_directories(spl PUBLIC ${CMAKE_CURRENT_LIST_DIR}/..)\ntarget_link_libraries(spl PUBLIC toolchain::nrf52 bluetoe::utility)\n\ntarget_sources(spl PRIVATE temperature.cpp)"
  },
  {
    "path": "examples/spl/README.md",
    "content": "Standard Peripheral Library\n---------------------------\n\nThis is a very small library that should provide plattform (toolchain and hardware) independen wrappers, that should make the examples provided, buildable on all plattform that support the required features."
  },
  {
    "path": "examples/spl/flash.hpp",
    "content": ""
  },
  {
    "path": "examples/spl/gpio.hpp",
    "content": "#ifndef SPL_GPIO_HPP\n#define SPL_GPIO_HPP\n\n#include <bluetoe/meta_tools.hpp>\n\n#include <type_traits>\n\n#include <nrf.h>\n\nnamespace spl {\n\n    namespace details {\n        struct valid_input_pin_parameter_meta_type {};\n        struct valid_output_pin_parameter_meta_type {};\n        struct output_inverter_meta_type {};\n        struct input_inverter_meta_type {};\n        struct pin_address_meta_type {};\n        struct pin_pullup_config_meta_type {};\n        struct pin_initial_output_activity_meta_type {};\n    }\n\n    /**\n     * @brief an input pin\n     */\n    template < typename ... Options >\n    struct input_pin\n    {\n    public:\n        input_pin();\n\n        bool value();\n    };\n\n    /**\n     * @brief inverts the output corresponding to the given value\n     */\n    struct inverted_input {\n        struct meta_type\n            : details::valid_input_pin_parameter_meta_type\n            , details::input_inverter_meta_type\n        {};\n\n        static bool invert( bool b )\n        {\n            return !b;\n        }\n    };\n\n    struct not_inverted_input {\n        struct meta_type\n            : details::valid_input_pin_parameter_meta_type\n            , details::input_inverter_meta_type\n        {};\n\n        static bool invert( bool b )\n        {\n            return b;\n        }\n    };\n\n    struct enable_pullup {\n        struct meta_type\n            : details::valid_input_pin_parameter_meta_type\n            , details::pin_pullup_config_meta_type\n        {};\n\n    };\n\n    struct no_pullup {\n        struct meta_type\n            : details::valid_input_pin_parameter_meta_type\n            , details::pin_pullup_config_meta_type\n        {};\n\n    };\n\n    struct not_inverted_output {\n        struct meta_type\n            : details::valid_output_pin_parameter_meta_type\n            , details::output_inverter_meta_type\n        {};\n\n        static bool invert( bool b )\n        {\n            return b;\n        }\n    };\n\n    struct initial_output_active {\n        struct meta_type\n            : details::valid_output_pin_parameter_meta_type\n            , details::pin_initial_output_activity_meta_type\n        {};\n    };\n\n    struct initial_output_inactive {\n        struct meta_type\n            : details::valid_output_pin_parameter_meta_type\n            , details::pin_initial_output_activity_meta_type\n        {};\n    };\n\n    template < typename ... Options >\n    struct output_pin\n    {\n    public:\n        output_pin();\n\n        void value( bool new_value );\n\n    private:\n        static_assert( std::is_same<\n                typename bluetoe::details::find_by_not_meta_type<\n                    details::valid_output_pin_parameter_meta_type,\n                    Options...\n                >::type, bluetoe::details::no_such_type\n            >::value, \"Parameter passed to a output_pin that is not a valid output_pin option!\" );\n\n        using inverter = typename bluetoe::details::find_by_meta_type< details::output_inverter_meta_type, Options..., not_inverted_output >::type;\n        using pin      = typename bluetoe::details::find_by_meta_type< details::pin_address_meta_type, Options... >::type;\n        using pullup   = typename bluetoe::details::find_by_meta_type< details::pin_pullup_config_meta_type, Options..., no_pullup >::type;\n        using init_val = typename bluetoe::details::find_by_meta_type< details::pin_initial_output_activity_meta_type, Options..., initial_output_inactive >::type;\n\n        static_assert( !std::is_same< pin, bluetoe::details::no_such_type >::value, \"Missing PIN configuration.\" );\n\n        static constexpr bool use_pullup     = std::is_same< pullup, enable_pullup >::value;\n        static constexpr bool initial_active = std::is_same< init_val, initial_output_active >::value;\n    };\n\n    /**\n     * @brief inverts the output corresponding to the given value\n     */\n    struct inverted_output {\n        struct meta_type\n            : details::valid_output_pin_parameter_meta_type\n            , details::output_inverter_meta_type\n        {};\n\n        static bool invert( bool b )\n        {\n            return not b;\n        }\n    };\n\n    /**\n     * @brief a pin for an input or output on port0\n     */\n    template < std::uint32_t Pin >\n    struct pin_p0 {\n        struct meta_type\n            : details::valid_output_pin_parameter_meta_type\n            , details::pin_address_meta_type\n        {};\n\n        static constexpr std::uint32_t base_address = NRF_P0_BASE;\n\n        template < bool Pullup >\n        static void init_output( bool start_value )\n        {\n            set( start_value );\n\n            reinterpret_cast< NRF_GPIO_Type* >( base_address )->PIN_CNF[ Pin ] =\n                ( ( Pullup ? GPIO_PIN_CNF_PULL_Pullup : GPIO_PIN_CNF_PULL_Disabled ) << GPIO_PIN_CNF_PULL_Pos )\n              | ( GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos );\n        }\n\n        static void set( bool new_value )\n        {\n            if ( new_value )\n                reinterpret_cast< NRF_GPIO_Type* >( base_address )->OUTSET = ( 1 << Pin );\n            else\n                reinterpret_cast< NRF_GPIO_Type* >( base_address )->OUTCLR = ( 1 << Pin );\n        }\n    };\n\n    // implementation:\n    template < typename ... Options >\n    output_pin< Options... >::output_pin()\n    {\n        pin::template init_output< use_pullup >( inverter::invert( initial_active ) );\n    }\n\n    template < typename ... Options >\n    void output_pin< Options... >::value( bool new_value )\n    {\n        pin::set( inverter::invert( new_value ) );\n    }\n}\n\n#endif\n"
  },
  {
    "path": "examples/spl/temperature.cpp",
    "content": "#include \"spl/temperature.hpp\"\n\n#include <nrf.h>\n\nstatic std::uint32_t sensor_value = 0;\n\nvoid spl::details::nrf52_temperature_base::init()\n{\n    NVIC_SetPriority( TEMP_IRQn, 3 );\n    NVIC_ClearPendingIRQ( TEMP_IRQn );\n    NVIC_EnableIRQ( TEMP_IRQn );\n    NRF_TEMP->INTENSET    = TEMP_INTENSET_DATARDY_Set;\n    NRF_TEMP->TASKS_START = 1;\n}\n\nstd::uint32_t spl::details::nrf52_temperature_base::value()\n{\n    return NRF_TEMP->TEMP;\n}\n\nextern \"C\" void TEMP_IRQHandler(void)\n{\n    NRF_TEMP->EVENTS_DATARDY = 0;\n    NRF_TEMP->TASKS_START = 1;\n}\n"
  },
  {
    "path": "examples/spl/temperature.hpp",
    "content": "#ifndef SPL_TEMPERATURE_HPP\n#define SPL_TEMPERATURE_HPP\n\n#include <cstdint>\n\nnamespace spl {\n\n    namespace details {\n        class nrf52_temperature_base\n        {\n        public:\n            static void init();\n            static std::uint32_t value();\n        };\n    }\n\n    /**\n     * @brief abstraction of a temperature sensing device\n     *\n     * Potential options could be resolution, bus to connect the sensor and so on...\n     */\n    template < typename ... Options >\n    class temperature : private details::nrf52_temperature_base\n    {\n    public:\n        temperature();\n\n        std::uint32_t value();\n\n        bool handle_event();\n    };\n\n\n    // implementation\n    template < typename ... Options >\n    temperature< Options... >::temperature()\n    {\n        init();\n    }\n\n    template < typename ... Options >\n    std::uint32_t temperature< Options... >::value()\n    {\n        return nrf52_temperature_base::value();\n    }\n\n    template < typename ... Options >\n    bool temperature< Options... >::handle_event()\n    {\n        return false;\n    }\n}\n\n#endif\n"
  },
  {
    "path": "examples/spl/timer.hpp",
    "content": "#ifndef SPL_TIMER_HPP\n#define SPL_TIMER_HPP\n\nnamespace spl {\n\n    template < typename ... Options >\n    class timer\n    {\n    public:\n        bool handle_event();\n    };\n}\n\n#endif\n"
  },
  {
    "path": "examples/synchronized_callbacks.cpp",
    "content": "/*\n * Example of callbacks that are synchronized to the connection event.\n *\n * API Documentation: link_layer/include/bluetoe/connection_event_callback.hpp\n */\n\n#include <bluetoe/server.hpp>\n#include <bluetoe/device.hpp>\n\n#include <bluetoe/connection_event_callback.hpp>\n\n#include <nrf.h>\n\nusing namespace bluetoe;\n\n// LED1 on a nRF52 eval board\nstatic constexpr int io_pin = 19;\n\n// GPIO\nstatic constexpr int io_event = 20;\n\nstatic void set_io( int pin, bool value )\n{\n    if ( value )\n    {\n        NRF_GPIO->OUTSET = 1 << pin;\n    }\n    else\n    {\n        NRF_GPIO->OUTCLR = 1 << pin;\n    }\n}\n\nstatic NRF_TIMER_Type& toggle_timer  = *NRF_TIMER2;\n\nstatic std::uint8_t io_pin_write_handler( bool state )\n{\n    // on an nRF52 eval board, the pin is connected to the LED's cathode, this inverts the logic.\n    set_io( io_pin, !state );\n\n    return error_codes::success;\n}\n\n/*\n * Type as set of callbacks\n */\nstruct callback_handler_t {\n    /*\n     * User defined type to keep connection releated informations\n     */\n    struct connection {\n        connection() : count( 0 ) {}\n        int count;\n    };\n\n    unsigned ll_synchronized_callback( unsigned instant, connection& con )\n    {\n        if ( instant == 0 )\n        {\n            con.count = ( con.count + 1 ) % 3;\n\n        }\n\n        for ( int i = 0; i != con.count + 1; ++i )\n        {\n            set_io( io_event, true );\n            set_io( io_event, false );\n        }\n\n        // Number of calls to skip\n        return con.count;\n    }\n};\n\nusing blinky_server = server<\n    service<\n        service_uuid< 0xC11169E1, 0x6252, 0x4450, 0x931C, 0x1B43A318783B >,\n        characteristic<\n            free_write_handler< bool, io_pin_write_handler >\n        >\n    >\n>;\n\n// Instance of callback handler\ncallback_handler_t callback_handler;\n\ndevice<\n    blinky_server,\n    link_layer::buffer_sizes< 200, 200 >,\n    bluetoe::link_layer::synchronized_connection_event_callback<\n        callback_handler_t, callback_handler, 4000u, -1000, 20u >,\n    bluetoe::link_layer::check_synchronized_connection_event_callback\n> gatt_srv;\n\nint main()\n{\n    static constexpr std::uint32_t timer_prescale_for_1us_resolution = 4;\n\n    toggle_timer.MODE        = TIMER_MODE_MODE_Timer << TIMER_MODE_MODE_Pos;\n    toggle_timer.BITMODE     = TIMER_BITMODE_BITMODE_32Bit;\n    toggle_timer.PRESCALER   = timer_prescale_for_1us_resolution;\n    toggle_timer.SHORTS      =\n        ( TIMER_SHORTS_COMPARE0_STOP_Enabled << TIMER_SHORTS_COMPARE0_STOP_Pos )\n     || ( TIMER_SHORTS_COMPARE0_CLEAR_Enabled << TIMER_SHORTS_COMPARE0_CLEAR_Pos );\n\n    toggle_timer.TASKS_STOP  = 1;\n    toggle_timer.TASKS_CLEAR = 1;\n    toggle_timer.INTENSET    = TIMER_INTENSET_COMPARE0_Enabled << TIMER_INTENSET_COMPARE0_Pos;\n\n    toggle_timer.CC[ 0 ]     = 5 * 1000 * 1000;\n\n    NVIC_ClearPendingIRQ( TIMER2_IRQn );\n    NVIC_EnableIRQ( TIMER2_IRQn );\n\n    toggle_timer.TASKS_START = 1;\n\n    // Init GPIO pins\n    for ( const auto pin: { io_pin, io_event } )\n    {\n        NRF_GPIO->PIN_CNF[ pin ] =\n            ( GPIO_PIN_CNF_DRIVE_S0H1 << GPIO_PIN_CNF_DRIVE_Pos ) |\n            ( GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos );\n    }\n\n    for ( ;; )\n        gatt_srv.run();\n}\n\nextern \"C\" void TIMER2_IRQHandler()\n{\n    toggle_timer.EVENTS_COMPARE[ 0 ] = 0;\n    toggle_timer.TASKS_START = 1;\n\n    static bool on = true;\n\n    if ( on )\n    {\n        gatt_srv.restart_synchronized_connection_event_callbacks();\n    }\n    else\n    {\n        gatt_srv.stop_synchronized_connection_event_callbacks();\n    }\n\n    on = !on;\n}\n"
  },
  {
    "path": "examples/thermometer.cpp",
    "content": "/**\n * @example thermometer.cpp\n *\n * This example demonstrates, how notifications work in Bluetoe. To send out a notification\n * one of the server::notify() functions has to be called. Bluetoe uses then the existing read\n * handler to send out the notification.\n *\n * The example also uses a connection callback to set the connection to 2MBit.\n */\n\n#include <bluetoe/server.hpp>\n#include <bluetoe/device.hpp>\n\n#include \"resources.hpp\"\n\nstd::int32_t temperature_value = 0x12345678;\nstatic constexpr char server_name[] = \"Temperature\";\nstatic constexpr char char_name[] = \"Temperature Value\";\n\nusing small_temperature_service = bluetoe::server<\n    bluetoe::server_name< server_name >,\n    bluetoe::service<\n        bluetoe::service_uuid< 0x8C8B4094, 0x0000, 0x499F, 0xA28A, 0x4EED5BC73CA9 >,\n        bluetoe::characteristic<\n            bluetoe::characteristic_uuid< 0xF0E6EBE6, 0x3749, 0x41A6, 0xB190, 0x591B262AC20A >,\n            bluetoe::no_write_access,\n            bluetoe::notify,\n            bluetoe::characteristic_name< char_name >,\n            bluetoe::bind_characteristic_value< decltype( temperature_value ), &temperature_value >\n        >\n    >\n>;\n\nvoid start_temperatur_messurement();\n\nstruct callbacks_t {\n    template < typename ConnectionData >\n    void ll_connection_established(\n        const bluetoe::link_layer::connection_details&   details,\n        const bluetoe::link_layer::connection_addresses& addresses,\n              ConnectionData&                            connection );\n\n} callbacks;\n\nbluetoe::device<\n    small_temperature_service,\n    bluetoe::link_layer::advertising_interval< 250u >,\n    bluetoe::link_layer::static_address< 0xf0, 0xa6, 0xd5, 0x4f, 0x60, 0x0b >,\n    bluetoe::link_layer::connection_callbacks< callbacks_t, callbacks >\n> server;\n\ntemplate < typename ConnectionData >\nvoid callbacks_t::ll_connection_established(\n    const bluetoe::link_layer::connection_details&   ,\n    const bluetoe::link_layer::connection_addresses& ,\n          ConnectionData&                             )\n{\n    server.phy_update_request_to_2mbit();\n}\n\nstatic examples::temperature temperature_sensor;\n\nint main()\n{\n\n    for ( ; ; )\n    {\n        server.run();\n\n        temperature_sensor.handle_event();\n\n        const std::int32_t new_value = temperature_sensor.value();\n        const auto delta = std::abs( new_value - temperature_value );\n\n        if ( delta >= 3 )\n        {\n            temperature_value = new_value;\n            server.notify( temperature_value );\n        }\n    }\n}\n"
  },
  {
    "path": "examples/ucontroller.hpp",
    "content": "#ifndef BLUETOE_EXAMPLES_UCONTROLLER_HPP\n#define BLUETOE_EXAMPLES_UCONTROLLER_HPP\n\n#if !defined BLUETOE_CONTROLLER\n#   if defined BLUETOE_BOARD_PCA10056\n#   elif defined BLUETOE_BOARD_PCA10040\n#   else\n#       error \"can't deduce used microcontroller from board. Please define BLUETOE_CONTROLLER\"\n#   endif\n#endif // include guard\n"
  },
  {
    "path": "publish-doxygen",
    "content": "# leave the script if we build on travis-ci and this is not the clang++-3.7 build\nif [[ $BUILD_ON_TRAVIS ]] && [[ \"$COMPILER\" != \"$BUILD_DOXYGEN_COMPILE\" ]]; then\n    exit\nfi\n\nif [[ $BUILD_ON_TRAVIS ]]; then\n    git clone https://github.com/doxygen/doxygen.git\n    cd doxygen\n    mkdir build\n    cd build\n    cmake -G \"Unix Makefiles\" ..\n    make\n    cd ..\nfi\n\n# see for the idea behin this script http://blog.gockelhut.com/2014/09/automatic-documentation-publishing-with.html\nREPO_PATH=git@github.com:TorstenRobitzki/bluetoe.git\nHTML_PATH=documentation/html\nCOMMIT_USER=\"Documentation Builder\"\nCOMMIT_EMAIL=\"travis@robitzki.de\"\nCHANGESET=$(git rev-parse --verify HEAD)\n\nROOT=\"$PWD\"\n\n# code github pages\nrm -rf ${HTML_PATH}\nmkdir -p ${HTML_PATH}\ngit clone -b gh-pages \"${REPO_PATH}\" --single-branch ${HTML_PATH}\n\n# remove old content\ncd ${HTML_PATH} && git rm -rf .\n\n# generate new documentation\ncd \"$ROOT\" && doxygen 1> /dev/null\n\n# commit new documentation\ncd ${HTML_PATH} \\\n    && git add . \\\n    && git config user.name \"${COMMIT_USER}\" \\\n    && git config user.email \"${COMMIT_EMAIL}\" \\\n    && git commit -m \"Automated documentation build for changeset ${CHANGESET}.\" \\\n    && git push origin gh-pages\n"
  },
  {
    "path": "tests/CMakeLists.txt",
    "content": "#set(Boost_DEBUG 1)\nfind_package( Boost REQUIRED )\n\nadd_compile_options(-Wall -pedantic -Wextra -Wfatal-errors)\n\nif (CMAKE_CXX_COMPILER_ID STREQUAL Clang OR CMAKE_CXX_COMPILER_ID STREQUAL AppleClang)\n    add_compile_options(-fsanitize=address)\n    add_link_options(-fsanitize=address)\nendif()\n\nadd_subdirectory(test_tools)\n\nfunction(add_and_register_test test_runner)\n    add_executable(${test_runner} ${test_runner}.cpp)\n\n    target_include_directories(${test_runner} SYSTEM PRIVATE ${Boost_INCLUDE_DIR})\n    target_link_libraries(${test_runner} PRIVATE bluetoe::iface bluetoe::sm bluetoe::utility test::tools)\n    target_compile_features(${test_runner} PRIVATE cxx_std_11)\n\n    if (BLUETOE_EXCLUDE_SLOW_TESTS)\n        target_compile_definitions(${test_runner} PRIVATE BLUETOE_EXCLUDE_SLOW_TESTS)\n    endif()\n\n    add_test(${test_runner} ./${test_runner})\nendfunction()\n\nfunction(bluetoe_add_test test_runner)\n    add_and_register_test(${test_runner} bluetoe::iface)\nendfunction()\n\nadd_and_register_test(write_queue_tests)\nadd_and_register_test(service_tests)\nadd_and_register_test(options_tests)\nadd_and_register_test(characteristic_tests)\nadd_and_register_test(characteristic_value_tests)\nadd_and_register_test(advertising_tests)\nadd_and_register_test(filter_tests)\nadd_and_register_test(server_tests)\nadd_and_register_test(auto_uuid_tests)\nadd_and_register_test(scattered_access_tests)\nadd_and_register_test(gap_service_tests)\nadd_and_register_test(read_write_handler_tests)\nadd_and_register_test(encryption_tests)\nadd_and_register_test(attribute_handle_tests)\nadd_and_register_test(l2cap_tests)\nadd_and_register_test(notification_queue_tests)\nadd_and_register_test(bits_tests)\nadd_and_register_test(ring_tests)\n\nadd_subdirectory(att)\nadd_subdirectory(link_layer)\nadd_subdirectory(services)\nadd_subdirectory(security_manager)\nadd_subdirectory(hci)\n"
  },
  {
    "path": "tests/advertising_tests.cpp",
    "content": "#include <bluetoe/custom_advertising.hpp>\n#include <bluetoe/adv_service_list.hpp>\n\n#define BOOST_TEST_MODULE\n#include <boost/test/included/unit_test.hpp>\n\n#include \"test_servers.hpp\"\n\ntemplate < class Server >\nvoid expected_advertising( std::initializer_list< std::uint8_t > expected, const Server& server, std::size_t buffer_size = 31 )\n{\n    std::vector< std::uint8_t > buffer( buffer_size );\n    const std::size_t size = server.advertising_data( &*buffer.begin(), buffer.size() );\n\n    BOOST_CHECK_EQUAL_COLLECTIONS( std::begin( buffer ), std::begin( buffer ) + size, expected.begin(), expected.end() );\n}\n\ntemplate < class Server >\nvoid expected_scan_response( std::initializer_list< std::uint8_t > expected, const Server& server, std::size_t buffer_size = 31 )\n{\n    std::vector< std::uint8_t > buffer( buffer_size );\n    const std::size_t size = server.scan_response_data( &*buffer.begin(), buffer.size() );\n\n    BOOST_CHECK_EQUAL_COLLECTIONS( std::begin( buffer ), std::begin( buffer ) + size, expected.begin(), expected.end() );\n}\n\nBOOST_AUTO_TEST_SUITE( server_name )\n\nstatic constexpr char name[] = \"Test Name\";\n\ntypedef bluetoe::extend_server<\n    test::small_temperature_service,\n    bluetoe::no_list_of_service_uuids,\n    bluetoe::server_name< name >\n> named_temperature_service;\n\nBOOST_FIXTURE_TEST_CASE( named_server, named_temperature_service )\n{\n    expected_advertising({\n        0x02, 0x01, 0x06,\n        0x0A, 0x09, 'T', 'e', 's', 't', ' ', 'N', 'a', 'm', 'e',\n        0x00, 0x00\n    }, *this );\n}\n\nBOOST_FIXTURE_TEST_CASE( short_named_server, named_temperature_service )\n{\n    expected_advertising( {\n        0x02, 0x01, 0x06,\n        0x06, 0x08, 'T', 'e', 's', 't', ' '\n    }, *this, 10 );\n}\n\ntypedef bluetoe::extend_server<\n    test::small_temperature_service,\n    bluetoe::no_list_of_service_uuids\n> unnamed_temperature_service;\n\nBOOST_FIXTURE_TEST_CASE( unnamed_server, unnamed_temperature_service )\n{\n    expected_advertising( {\n        0x02, 0x01, 0x06, 0x00, 0x00\n    }, *this );\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE( service_list )\n\nusing no_uuids_server = bluetoe::server<\n    bluetoe::service<\n        bluetoe::service_uuid16< 0x1212 >\n    >,\n    bluetoe::no_list_of_service_uuids\n>;\n\nBOOST_FIXTURE_TEST_CASE( no_uuid_list, no_uuids_server )\n{\n    expected_advertising( {\n        0x02, 0x01, 0x06, 0x00, 0x00\n    }, *this );\n}\n\nusing one_uuid_server = bluetoe::server<\n    bluetoe::service<\n        bluetoe::service_uuid16< 0x1234 >\n    >,\n    bluetoe::list_of_16_bit_service_uuids<\n        bluetoe::service_uuid16< 0x1234 >\n    >\n>;\n\nBOOST_FIXTURE_TEST_CASE( uuid_with_one_element, one_uuid_server )\n{\n    expected_advertising( {\n        0x02, 0x01, 0x06,\n        0x03, 0x03, 0x34, 0x12,\n        0x00, 0x00\n    }, *this );\n}\n\nusing two_uuid_server = bluetoe::server<\n    bluetoe::service<\n        bluetoe::service_uuid16< 0x1234 >\n    >,\n    bluetoe::service<\n        bluetoe::service_uuid16< 0xabcd >\n    >,\n    bluetoe::list_of_16_bit_service_uuids<\n        bluetoe::service_uuid16< 0x1234 >,\n        bluetoe::service_uuid16< 0xabcd >\n    >\n>;\n\nBOOST_FIXTURE_TEST_CASE( uuid_with_two_element, two_uuid_server )\n{\n    expected_advertising( {\n        0x02, 0x01, 0x06,\n        0x05, 0x03, 0x34, 0x12, 0xcd, 0xab,\n        0x00, 0x00\n    }, *this );\n}\n\nusing no_element_server = bluetoe::server<\n    bluetoe::service<\n        bluetoe::service_uuid16< 0x1212 >\n    >,\n    bluetoe::list_of_16_bit_service_uuids<\n    >\n>;\n\n\nBOOST_FIXTURE_TEST_CASE( uuid_with_no_element, no_element_server )\n{\n    expected_advertising( {\n        0x02, 0x01, 0x06,\n        0x00, 0x00\n    }, *this );\n}\n\nusing three_uuid_server = bluetoe::extend_server<\n    test::small_temperature_service,\n    bluetoe::list_of_16_bit_service_uuids<\n        bluetoe::service_uuid16< 0x1234 >,\n        bluetoe::service_uuid16< 0xabcd >,\n        bluetoe::service_uuid16< 0x0102 >\n    >\n>;\n\nBOOST_FIXTURE_TEST_CASE( shortened_list, three_uuid_server )\n{\n    expected_advertising( {\n        0x02, 0x01, 0x06,\n        0x05, 0x02, 0x34, 0x12, 0xcd, 0xab\n    }, *this, 9 );\n}\n\nBOOST_FIXTURE_TEST_CASE( no_space_left_for_a_single_uuid, three_uuid_server )\n{\n    expected_advertising( {\n        0x02, 0x01, 0x06,\n        0x00, 0x00\n    }, *this, 6 );\n}\n\nusing server_with_multiple_services = bluetoe::server<\n    bluetoe::service<\n        bluetoe::service_uuid16< 0x1122 >\n    >\n>;\n\nBOOST_FIXTURE_TEST_CASE( implicit_service_list, server_with_multiple_services )\n{\n    expected_advertising( {\n        0x02, 0x01, 0x06,\n        0x05, 0x03, 0x22, 0x11, 0x00, 0x18,\n        0x00, 0x00\n    }, *this );\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE( service_list_128 )\n\nusing no_uuids_server = bluetoe::extend_server<\n    test::small_temperature_service,\n    bluetoe::no_list_of_service_uuids\n>;\n\nBOOST_FIXTURE_TEST_CASE( no_uuid_list, no_uuids_server )\n{\n    expected_advertising( {\n        0x02, 0x01, 0x06, 0x00, 0x00\n    }, *this );\n}\n\nusing one_uuid_server = bluetoe::extend_server<\n    test::small_temperature_service,\n    bluetoe::list_of_128_bit_service_uuids<\n        bluetoe::service_uuid< 0x111393DD, 0x01D2, 0x40D6, 0xA0A0, 0xE9B1A56A1191 >\n    >\n>;\n\nBOOST_FIXTURE_TEST_CASE( uuid_with_one_element, one_uuid_server )\n{\n    expected_advertising( {\n        0x02, 0x01, 0x06,\n        0x11, 0x07,\n        0x91, 0x11, 0x6A, 0xA5,\n        0xB1, 0xE9, 0xA0, 0xA0,\n        0xD6, 0x40, 0xD2, 0x01,\n        0xDD, 0x93, 0x13, 0x11,\n        0x00, 0x00\n    }, *this );\n}\n\nusing two_uuid_server = bluetoe::extend_server<\n    test::small_temperature_service,\n    bluetoe::list_of_128_bit_service_uuids<\n        bluetoe::service_uuid< 0x111393DD, 0x01D2, 0x40D6, 0xA0A0, 0xE9B1A56A1191 >,\n        bluetoe::service_uuid< 0x221393DD, 0x01D2, 0x40D6, 0xA0A0, 0xE9B1A56A1177 >\n    >\n>;\n\n/*\n * This is more or less a theoretical test, as there will never fit two 16 byte UUIDs into the advertising data\n */\nBOOST_FIXTURE_TEST_CASE( uuid_with_two_element, two_uuid_server )\n{\n    expected_advertising( {\n        0x02, 0x01, 0x06,\n        0x21, 0x07,\n        0x91, 0x11, 0x6A, 0xA5,\n        0xB1, 0xE9, 0xA0, 0xA0,\n        0xD6, 0x40, 0xD2, 0x01,\n        0xDD, 0x93, 0x13, 0x11,\n        0x77, 0x11, 0x6A, 0xA5,\n        0xB1, 0xE9, 0xA0, 0xA0,\n        0xD6, 0x40, 0xD2, 0x01,\n        0xDD, 0x93, 0x13, 0x22,\n        0x00, 0x00\n    }, *this, 100 );\n}\n\nusing no_uuid_server = bluetoe::extend_server<\n    test::small_temperature_service,\n    bluetoe::list_of_128_bit_service_uuids<\n    >\n>;\n\nBOOST_FIXTURE_TEST_CASE( uuid_with_no_element, no_uuid_server )\n{\n    expected_advertising( {\n        0x02, 0x01, 0x06,\n        0x00, 0x00\n    }, *this );\n}\n\nBOOST_FIXTURE_TEST_CASE( shortened_list, two_uuid_server )\n{\n    expected_advertising( {\n        0x02, 0x01, 0x06,\n        0x11, 0x06,\n        0x91, 0x11, 0x6A, 0xA5,\n        0xB1, 0xE9, 0xA0, 0xA0,\n        0xD6, 0x40, 0xD2, 0x01,\n        0xDD, 0x93, 0x13, 0x11,\n        0x00, 0x00\n    }, *this );\n}\n\nBOOST_FIXTURE_TEST_CASE( no_space_left_for_a_single_uuid, two_uuid_server )\n{\n    expected_advertising( {\n        0x02, 0x01, 0x06,\n        0x00, 0x00\n    }, *this, 6 );\n}\n\nusing server_with_multiple_services = bluetoe::server<\n    bluetoe::service<\n        bluetoe::service_uuid< 0x111393DD, 0x01D2, 0x40D6, 0xA0A0, 0xE9B1A56A1191 >\n    >\n>;\n\nBOOST_FIXTURE_TEST_CASE( implicit_service_list, server_with_multiple_services )\n{\n    expected_advertising( {\n        0x02, 0x01, 0x06,\n        0x03, 0x03, 0x00, 0x18,\n        0x11, 0x07,\n        0x91, 0x11, 0x6A, 0xA5,\n        0xB1, 0xE9, 0xA0, 0xA0,\n        0xD6, 0x40, 0xD2, 0x01,\n        0xDD, 0x93, 0x13, 0x11,\n        0x00, 0x00\n    }, *this );\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE( peripheral_connection_interval_range )\n\nusing unspecifed_range = bluetoe::extend_server<\n    test::small_temperature_service,\n    bluetoe::no_list_of_service_uuids,\n    bluetoe::peripheral_connection_interval_range<>\n>;\n\nBOOST_FIXTURE_TEST_CASE( unspecified_range_encoding, unspecifed_range )\n{\n    expected_advertising( {\n        0x02, 0x01, 0x06,\n        0x05, 0x12, 0xff, 0xff, 0xff, 0xff,\n        0x00, 0x00\n    }, *this );\n}\n\nusing specifed_range = bluetoe::extend_server<\n    test::small_temperature_service,\n    bluetoe::no_list_of_service_uuids,\n    bluetoe::peripheral_connection_interval_range< 0x0102, 0x203 >\n>;\n\nBOOST_FIXTURE_TEST_CASE( specific_range_encoding, specifed_range )\n{\n    expected_advertising( {\n        0x02, 0x01, 0x06,\n        0x05, 0x12, 0x02, 0x01, 0x03, 0x02,\n        0x00, 0x00\n    }, *this );\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE( custom_advertisings )\n\nstatic const std::uint8_t custom_advertising_data[] = {\n    0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07\n};\n\nstatic const std::uint8_t custom_response_data[] = {\n    0x11, 0x22, 0x33, 0x44, 0x55\n};\n\nusing custom_advertising = bluetoe::extend_server<\n    test::small_temperature_service,\n    bluetoe::custom_advertising_data< sizeof( custom_advertising_data ), custom_advertising_data >,\n    bluetoe::custom_scan_response_data< sizeof( custom_response_data ), custom_response_data >\n>;\n\nBOOST_FIXTURE_TEST_CASE( custom_advertising_test, custom_advertising )\n{\n    expected_advertising( {\n        0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07\n    }, *this );\n}\n\nBOOST_FIXTURE_TEST_CASE( custom_scan_response_test, custom_advertising )\n{\n    expected_scan_response( {\n        0x11, 0x22, 0x33, 0x44, 0x55\n    }, *this );\n}\n\nusing runtime_custom_advertising = bluetoe::extend_server<\n    test::small_temperature_service,\n    bluetoe::runtime_custom_advertising_data,\n    bluetoe::runtime_custom_scan_response_data\n>;\n\nBOOST_FIXTURE_TEST_CASE( runtime_custom_advertising_test_default, runtime_custom_advertising )\n{\n    expected_advertising( {\n    }, *this );\n}\n\nBOOST_FIXTURE_TEST_CASE( runtime_custom_advertising_test, runtime_custom_advertising )\n{\n    static constexpr std::uint8_t data[] = {\n        0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,\n        0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,\n        0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,\n        0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e\n    };\n\n    BOOST_CHECK( !advertising_or_scan_response_data_has_been_changed() );\n    set_runtime_custom_advertising_data( &data[ 0 ], 0x1f );\n    BOOST_CHECK( advertising_or_scan_response_data_has_been_changed() );\n    BOOST_CHECK( !advertising_or_scan_response_data_has_been_changed() );\n\n    expected_advertising( {\n        0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,\n        0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,\n        0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,\n        0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e\n    }, *this );\n}\n\nBOOST_FIXTURE_TEST_CASE( runtime_custom_scan_response_test_default, runtime_custom_advertising )\n{\n    expected_scan_response( {}, *this );\n}\n\nBOOST_FIXTURE_TEST_CASE( runtime_custom_scan_response_test, runtime_custom_advertising )\n{\n    static constexpr std::uint8_t data[] = {\n        0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,\n        0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,\n        0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,\n        0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e\n    };\n\n    BOOST_CHECK( !advertising_or_scan_response_data_has_been_changed() );\n    set_runtime_custom_scan_response_data( &data[ 0 ], 0x1f );\n    BOOST_CHECK( advertising_or_scan_response_data_has_been_changed() );\n    BOOST_CHECK( !advertising_or_scan_response_data_has_been_changed() );\n\n    expected_scan_response( {\n        0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,\n        0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,\n        0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,\n        0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e\n    }, *this );\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE( appearance_advertised )\n\nusing default_appearance_advertising = bluetoe::extend_server<\n    test::small_temperature_service,\n    bluetoe::no_list_of_service_uuids,\n    bluetoe::advertise_appearance >;\n\nBOOST_FIXTURE_TEST_CASE( by_default_unknown_is_used, default_appearance_advertising )\n{\n    expected_advertising( {\n        0x02, 0x01, 0x06,\n        0x03, 0x19, 0x00, 0x00,\n        0x00, 0x00\n    }, *this );\n}\n\nusing hoverboard_server = bluetoe::extend_server<\n    test::small_temperature_service,\n    bluetoe::appearance::location_pod,\n    bluetoe::no_list_of_service_uuids,\n    bluetoe::advertise_appearance >;\n\n\nBOOST_FIXTURE_TEST_CASE( configured_appearance, hoverboard_server )\n{\n    expected_advertising( {\n        0x02, 0x01, 0x06,\n        0x03, 0x19, 0x43, 0x14,\n        0x00, 0x00\n    }, *this );\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "tests/att/CMakeLists.txt",
    "content": "add_and_register_test(find_information_tests)\nadd_and_register_test(find_by_type_value_tests)\nadd_and_register_test(find_notification_data_tests)\nadd_and_register_test(read_tests)\nadd_and_register_test(read_by_group_type_tests)\nadd_and_register_test(read_by_type_tests)\nadd_and_register_test(write_tests)\nadd_and_register_test(mtu_exchange_tests)\nadd_and_register_test(read_blob_tests)\nadd_and_register_test(notification_tests)\nadd_and_register_test(read_multiple_tests)\nadd_and_register_test(write_command_tests)\nadd_and_register_test(prepare_write_tests)\nadd_and_register_test(execute_write_tests)\nadd_and_register_test(request_not_supported_tests)\nadd_and_register_test(indication_tests)\nadd_and_register_test(outgoing_priority_tests)\nadd_and_register_test(descriptor_tests)\n\ntarget_link_libraries(notification_tests PRIVATE bluetoe::link_layer)\n"
  },
  {
    "path": "tests/att/descriptor_tests.cpp",
    "content": "#include <bluetoe/descriptor.hpp>\n\n#define BOOST_TEST_MODULE\n#include <boost/test/included/unit_test.hpp>\n\n#include \"test_servers.hpp\"\n\nstd::uint16_t dummy_value;\n\nstatic const std::uint8_t descriptor_value[ 4 ] = { 0x01, 0x02, 0x03, 0x04 };\n\nusing server_with_single_descriptor_characterstic = bluetoe::server<\n    bluetoe::service<\n        bluetoe::service_uuid< 0x8C8B4094, 0x0DE2, 0x499F, 0xA28A, 0x4EED5BC73CA9 >,\n        bluetoe::characteristic<\n            bluetoe::characteristic_uuid< 0x8C8B4094, 0x0DE2, 0x499F, 0xA28A, 0x4EED5BC73CAA >,\n            bluetoe::bind_characteristic_value< decltype( dummy_value ), &dummy_value >,\n            bluetoe::descriptor< 0x4711, descriptor_value, sizeof( descriptor_value ) >\n        >\n    >\n>;\n\nBOOST_FIXTURE_TEST_CASE( single_descriptor, test::request_with_reponse< server_with_single_descriptor_characterstic > )\n{\n    l2cap_input({\n        0x0A,                       // read request\n        0x04, 0x00                  // handle\n    });\n\n    expected_result( {\n        0x0B,                       // read response\n        0x01, 0x02, 0x03, 0x04\n    });\n}\n\nBOOST_FIXTURE_TEST_CASE( read_by_type, test::request_with_reponse< server_with_single_descriptor_characterstic > )\n{\n    l2cap_input({\n        0x08,                       // Read By Type Request\n        0x01, 0x00,                 // First requested handle number\n        0xff, 0xff,                 // Last requested handle number\n        0x11, 0x47                  // UUID\n    });\n\n    expected_result( {\n        0x09,                       // Read By Type Response\n        0x06,                       // The size of each attribute handle- value pair\n        0x04, 0x00,                 // Handle\n        0x01, 0x02, 0x03, 0x04      // Value\n    });\n}\n\nBOOST_FIXTURE_TEST_CASE( read_blob, test::request_with_reponse< server_with_single_descriptor_characterstic > )\n{\n    l2cap_input({\n        0x0C,                       // Read Blob Request\n        0x04, 0x00,                 // handle\n        0x03, 0x00                  // Offset\n    });\n\n    expected_result( {\n        0x0D,                       // Read Blob Response\n        0x04                        // Value\n    });\n}\n\nBOOST_FIXTURE_TEST_CASE( write_only, test::request_with_reponse< server_with_single_descriptor_characterstic > )\n{\n    l2cap_input({\n        0x12,                       // Write Request\n        0x04, 0x00,                 // handle\n        0x01, 0x02, 0x03, 0x05      // new Value\n    });\n\n    expected_result( {\n        0x01,                       // Error Response\n        0x12,                       // request opcode\n        0x04, 0x00,                 // handle\n        0x03                        // Write Not Permitted\n    });\n}\n\nusing server_with_multiple_characterstics = bluetoe::server<\n    bluetoe::service<\n        bluetoe::service_uuid< 0x8C8B4094, 0x0DE2, 0x499F, 0xA28A, 0x4EED5BC73CA9 >,\n        bluetoe::characteristic<\n            bluetoe::characteristic_uuid< 0x8C8B4094, 0x0DE2, 0x499F, 0xA28A, 0x4EED5BC73CAA >,\n            bluetoe::bind_characteristic_value< decltype( dummy_value ), &dummy_value >,\n            bluetoe::descriptor< 0x4711, descriptor_value, sizeof( descriptor_value ) >\n        >,\n        bluetoe::characteristic<\n            bluetoe::characteristic_uuid< 0x8C8B4094, 0x0DE2, 0x499F, 0xA28A, 0x4EED5BC73CAB >,\n            bluetoe::bind_characteristic_value< decltype( dummy_value ), &dummy_value >\n        >\n    >\n>;\n\n/*\n * Make sure, that the enumeration of the attributes works even for characteristics that follow the\n * characteristic with the descriptor\n */\nBOOST_FIXTURE_TEST_CASE( read_second_char, test::request_with_reponse< server_with_multiple_characterstics > )\n{\n    // Characteristic Declaration of the second characteristic\n    l2cap_input({\n        0x0A,                       // read request\n        0x05, 0x00                  // handle\n    });\n\n    expected_result( {\n        0x0B,                       // read response\n        0x0A,                       // Properties: read, write\n        0x06, 0x00,                 // Value Attribute Handle\n        0xAB, 0x3C, 0xC7, 0x5B,     // Characteristic UUID\n        0xED, 0x4E, 0x8A, 0xA2,\n        0x9F, 0x49, 0xE2, 0x0D,\n        0x94, 0x40, 0x8B, 0x8C\n    });\n}\n\n/* Currently not supported\nstatic const std::uint8_t descriptor_value2[ 5 ] = { 0x10, 0x20, 0x30, 0x40, 0x50 };\nusing server_with_multiple_descriptor_characterstic = bluetoe::server<\n    bluetoe::service<\n        bluetoe::service_uuid< 0x8C8B4094, 0x0DE2, 0x499F, 0xA28A, 0x4EED5BC73CA9 >,\n        bluetoe::characteristic<\n            bluetoe::characteristic_uuid< 0x8C8B4094, 0x0DE2, 0x499F, 0xA28A, 0x4EED5BC73CAA >,\n            bluetoe::bind_characteristic_value< decltype( dummy_value ), &dummy_value >,\n            bluetoe::descriptor< 0x4711, descriptor_value, sizeof( descriptor_value ) >,\n            bluetoe::descriptor< 0x4712, descriptor_value2, sizeof( descriptor_value2 ) >\n        >\n    >\n>;\n\nBOOST_FIXTURE_TEST_CASE( multiple_descriptors, test::request_with_reponse< server_with_single_descriptor_characterstic > )\n{\n    l2cap_input({\n        0x0A,                       // read request\n        0x04, 0x00                  // handle\n    });\n\n    expected_result( {\n        0x0B,                       // read response\n        0x01, 0x02, 0x03, 0x04\n    });\n\n    l2cap_input({\n        0x0A,                       // read request\n        0x05, 0x00                  // handle\n    });\n\n    expected_result( {\n        0x0B,                       // read response\n        0x01, 0x02, 0x03, 0x04, 0x05\n    });\n}\n*/\n\n//BOOST_FIXTURE_TEST_CASE( offset_out_of_range )"
  },
  {
    "path": "tests/att/execute_write_tests.cpp",
    "content": "#define BOOST_TEST_MODULE\n#include <boost/test/included/unit_test.hpp>\n\n#include \"test_servers.hpp\"\n#include <array>\n\nBOOST_AUTO_TEST_SUITE( execute_write_errors )\n\nstd::uint8_t value = 0;\n\ntypedef bluetoe::server<\n    bluetoe::shared_write_queue< 100 >,\n    bluetoe::service<\n        bluetoe::service_uuid< 0x8C8B4094, 0x0DE2, 0x499F, 0xA28A, 0x4EED5BC73CA9 >,\n        bluetoe::characteristic<\n            bluetoe::characteristic_uuid< 0x8C8B4094, 0x0DE2, 0x499F, 0xA28A, 0x4EED5BC73CAA >,\n            bluetoe::bind_characteristic_value< decltype( value ), &value >\n        >\n    >\n> value_server;\n\nBOOST_FIXTURE_TEST_CASE( pdu_to_small, test::request_with_reponse< value_server > )\n{\n    BOOST_CHECK( check_error_response( { 0x18 }, 0x18, 0x0000, 0x04 ) );\n}\n\nBOOST_FIXTURE_TEST_CASE( pdu_to_large, test::request_with_reponse< value_server > )\n{\n    BOOST_CHECK( check_error_response( { 0x18, 0x00, 0x01 }, 0x18, 0x0000, 0x04 ) );\n}\n\nBOOST_FIXTURE_TEST_CASE( invalid_flags, test::request_with_reponse< value_server > )\n{\n    BOOST_CHECK( check_error_response( { 0x18, 0x02 }, 0x18, 0x0000, 0x04 ) );\n    BOOST_CHECK( check_error_response( { 0x18, 0x80 }, 0x18, 0x0000, 0x04 ) );\n}\n\nBOOST_FIXTURE_TEST_CASE( request_not_supported_if_no_buffer_exist, test::small_temperature_service_with_response<> )\n{\n    BOOST_CHECK( check_error_response( { 0x18, 0x00 }, 0x18, 0x0000, 0x06 ) );\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE( execute_write )\n\nstatic const std::array< std::uint8_t, 16 > value_org = { {\n    0x00, 0x01, 0x02, 0x03,\n    0x04, 0x05, 0x06, 0x07,\n    0x08, 0x09, 0x0A, 0x0B,\n    0x0C, 0x0D, 0x0E, 0x0F\n} };\n\nstd::array< std::uint8_t, 16 > value = value_org;\n\ntypedef bluetoe::server<\n    bluetoe::shared_write_queue< 100 >,\n    bluetoe::service<\n        bluetoe::service_uuid< 0x8C8B4094, 0x0DE2, 0x499F, 0xA28A, 0x4EED5BC73CA9 >,\n        bluetoe::characteristic<\n            bluetoe::characteristic_uuid< 0x8C8B4094, 0x0DE2, 0x499F, 0xA28A, 0x4EED5BC73CAA >,\n            bluetoe::bind_characteristic_value< decltype( value ), &value >\n        >\n    >\n> value_server;\n\nstruct server_fixture : test::request_with_reponse< value_server >\n{\n    server_fixture()\n    {\n        value = value_org;\n    }\n};\n\nBOOST_FIXTURE_TEST_CASE( no_queue_no_error, server_fixture )\n{\n    l2cap_input( { 0x18, 0x00 } );\n    expected_result( { 0x19 } );\n}\n\nBOOST_FIXTURE_TEST_CASE( no_queue_no_error_chancel, server_fixture )\n{\n    l2cap_input( { 0x18, 0x01 } );\n    expected_result( { 0x19 } );\n}\n\nstruct serval_writes : server_fixture\n{\n    serval_writes()\n    {\n        l2cap_input( { 0x16, 0x03, 0x00, 0x00, 0x00, 0x02, 0x01, 0x00 } );\n        l2cap_input( { 0x16, 0x03, 0x00, 0x08, 0x00, 0x0b, 0x88, 0x99 } );\n    }\n};\n\nBOOST_FIXTURE_TEST_CASE( no_change_if_canceled, serval_writes )\n{\n    l2cap_input( { 0x18, 0x00 } );\n    expected_result( { 0x19 } );\n\n    BOOST_CHECK_EQUAL_COLLECTIONS( std::begin( value ), std::end( value ), std::begin( value_org ), std::end( value_org ) );\n}\n\nBOOST_FIXTURE_TEST_CASE( changes_applied, serval_writes )\n{\n    l2cap_input( { 0x18, 0x01 } );\n    expected_result( { 0x19 } );\n\n    static const std::array< std::uint8_t, 16 > writes_applied = { {\n        0x02, 0x01, 0x00, 0x03,\n        0x04, 0x05, 0x06, 0x07,\n        0x0b, 0x88, 0x99, 0x0B,\n        0x0C, 0x0D, 0x0E, 0x0F\n    } };\n\n    BOOST_CHECK_EQUAL_COLLECTIONS( std::begin( value ), std::end( value ), writes_applied.begin(), writes_applied.end() );\n}\n\nBOOST_FIXTURE_TEST_CASE( no_changes_if_first_write_was_erroneous, server_fixture )\n{\n    // first prepare write will write over the end of the value\n    l2cap_input( { 0x16, 0x03, 0x00, 0x0E, 0x00, 0x02, 0x01, 0x00 } );\n    l2cap_input( { 0x16, 0x03, 0x00, 0x08, 0x00, 0x0b, 0x88, 0x99 } );\n\n    BOOST_CHECK( check_error_response( { 0x18, 0x01 }, 0x18, 0x0003, 0x0D ) );\n    BOOST_CHECK_EQUAL_COLLECTIONS( std::begin( value ), std::end( value ), std::begin( value_org ), std::end( value_org ) );\n}\n\nBOOST_FIXTURE_TEST_CASE( first_change_applied_if_second_write_was_erroneous, server_fixture )\n{\n    // first prepare write will write over the end of the value\n    l2cap_input( { 0x16, 0x03, 0x00, 0x00, 0x00, 0x02, 0x01, 0x00 } );\n    l2cap_input( { 0x16, 0x03, 0x00, 0x11, 0x00, 0x0b, 0x88, 0x99 } );\n\n    BOOST_CHECK( check_error_response( { 0x18, 0x01 }, 0x18, 0x0003, 0x07 ) );\n\n    static const std::array< std::uint8_t, 16 > expected_value = { {\n        0x02, 0x01, 0x00, 0x03,\n        0x04, 0x05, 0x06, 0x07,\n        0x08, 0x09, 0x0A, 0x0B,\n        0x0C, 0x0D, 0x0E, 0x0F\n    } };\n\n    BOOST_CHECK_EQUAL_COLLECTIONS( std::begin( value ), std::end( value ), std::begin( expected_value ), std::end( expected_value ) );\n}\n\nBOOST_FIXTURE_TEST_CASE( queue_is_release_after_executing, server_fixture )\n{\n    channel_data_t< bluetoe::details::link_state_no_security > other_client;\n    l2cap_input( { 0x16, 0x03, 0x00, 0x00, 0x00, 0x02, 0x01, 0x00 }, other_client );\n    expected_result( { 0x17, 0x03, 0x00, 0x00, 0x00, 0x02, 0x01, 0x00 } );\n}\n\nBOOST_FIXTURE_TEST_CASE( queue_is_release_after_canceling, serval_writes )\n{\n    l2cap_input( { 0x18, 0x00 } );\n\n    channel_data_t< bluetoe::details::link_state_no_security > other_client;\n    l2cap_input( { 0x16, 0x03, 0x00, 0x00, 0x00, 0x02, 0x01, 0x00 }, other_client );\n    expected_result( { 0x17, 0x03, 0x00, 0x00, 0x00, 0x02, 0x01, 0x00 } );\n}\n\nBOOST_FIXTURE_TEST_CASE( queue_is_release_after_an_error_occured, server_fixture )\n{\n    // first prepare write will write over the end of the value\n    l2cap_input( { 0x16, 0x03, 0x00, 0x0E, 0x00, 0x02, 0x01, 0x00 } );\n    l2cap_input( { 0x18, 0x01 } );\n\n    channel_data_t< bluetoe::details::link_state_no_security > other_client;\n    l2cap_input( { 0x16, 0x03, 0x00, 0x00, 0x00, 0x02, 0x01, 0x00 }, other_client );\n    expected_result( { 0x17, 0x03, 0x00, 0x00, 0x00, 0x02, 0x01, 0x00 } );\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n\n\nBOOST_AUTO_TEST_SUITE( execute_write_with_fixed_attribute_handles )\n\n    std::array< std::uint8_t, 16 > value = { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88 };\n\n    using value_server = bluetoe::server<\n        bluetoe::shared_write_queue< 100 >,\n        bluetoe::service<\n            bluetoe::service_uuid< 0x8C8B4094, 0x0DE2, 0x499F, 0xA28A, 0x4EED5BC73CA9 >,\n            bluetoe::characteristic<\n                bluetoe::attribute_handles< 0x030, 0x40 >,\n                bluetoe::characteristic_uuid< 0x8C8B4094, 0x0DE2, 0x499F, 0xA28A, 0x4EED5BC73CAA >,\n                bluetoe::bind_characteristic_value< decltype( value ), &value >\n            >\n        >\n    >;\n\n    BOOST_FIXTURE_TEST_CASE( write, test::request_with_reponse< value_server > )\n    {\n        // write\n        l2cap_input( { 0x16, 0x40, 0x00, 0x02, 0x00, 0xaa, 0xbb, 0xcc } );\n        expected_result( { 0x17, 0x40, 0x00, 0x02, 0x00, 0xaa, 0xbb, 0xcc } );\n\n        static const std::array< std::uint8_t, 16 > unchanged = { {\n            0x11, 0x22, 0x33, 0x44,\n            0x55, 0x66, 0x77, 0x88,\n            0x00, 0x00, 0x00, 0x00,\n            0x00, 0x00, 0x00, 0x00\n        } };\n\n        BOOST_CHECK_EQUAL_COLLECTIONS( std::begin( value ), std::end( value ), std::begin( unchanged ), std::end( unchanged ) );\n\n        // execute\n        l2cap_input( { 0x18, 0x01 } );\n\n        static const std::array< std::uint8_t, 16 > changed = { {\n            0x11, 0x22, 0xaa, 0xbb,\n            0xcc, 0x66, 0x77, 0x88,\n            0x00, 0x00, 0x00, 0x00,\n            0x00, 0x00, 0x00, 0x00\n        } };\n\n        BOOST_CHECK_EQUAL_COLLECTIONS( std::begin( value ), std::end( value ), std::begin( changed ), std::end( changed ) );\n    }\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "tests/att/find_by_type_value_tests.cpp",
    "content": "#define BOOST_TEST_MODULE\n#include <boost/test/included/unit_test.hpp>\n\n#include \"test_servers.hpp\"\n#include \"test_services.hpp\"\n\nBOOST_AUTO_TEST_SUITE( find_by_type_value_errors )\n\nBOOST_FIXTURE_TEST_CASE( start_handle_zero, test::small_temperature_service_with_response<> )\n{\n    BOOST_CHECK( check_error_response( { 0x06, 0x00, 0x00, 0xff, 0xff, 0x00, 0x28, 0x16, 0x18 }, 0x06, 0x0000, 0x01 ) );\n}\n\nBOOST_FIXTURE_TEST_CASE( start_handle_greater_than_end_handle, test::small_temperature_service_with_response<> )\n{\n    BOOST_CHECK( check_error_response( { 0x06, 0x05, 0x00, 0x04, 0x00, 0x00, 0x28, 0x16, 0x18 }, 0x06, 0x0005, 0x01 ) );\n}\n\nBOOST_FIXTURE_TEST_CASE( invalid_request_size, test::small_temperature_service_with_response<> )\n{\n    BOOST_CHECK( check_error_response( { 0x06, 0x05, 0x00, 0x04, 0x00, 0x00, 0x28, 0x16 }, 0x06, 0x0000, 0x04 ) );\n}\n\nBOOST_FIXTURE_TEST_CASE( handle_out_of_range, test::small_temperature_service_with_response<> )\n{\n    BOOST_CHECK( check_error_response( { 0x06, 0x40, 0x10, 0xff, 0xff, 0x00, 0x28, 0x16, 0x18 }, 0x06, 0x1040, 0x0A ) );\n}\n\nBOOST_FIXTURE_TEST_CASE( unsupprorted_group_type, test::small_temperature_service_with_response<> )\n{\n    // every type but the «Primary Service» is invalid for GATT\n    BOOST_CHECK( check_error_response( { 0x06, 0x01, 0x00, 0xff, 0xff, 0x01, 0x28, 0x16, 0x18 }, 0x06, 0x0001, 0x10 ) );\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE( find_by_type_value )\n\nBOOST_FIXTURE_TEST_CASE( discover_primary_service_by_service_uuid, test::request_with_reponse< test::three_apes_service > )\n{\n    l2cap_input({\n        0x06, 0x01, 0x00, 0xFF, 0xFF, 0x00, 0x28,\n        0xA9, 0x3C, 0xC7, 0x5B,     // Service UUID\n        0xED, 0x4E, 0x8A, 0xA2,\n        0x9F, 0x49, 0xE2, 0x0D,\n        0x94, 0x40, 0x8B, 0x8C\n    });\n\n    static const std::uint8_t expected_response[] = {\n        0x07,\n        0x01, 0x00,\n        0x07, 0x00\n    };\n\n    BOOST_CHECK_EQUAL_COLLECTIONS( &response[ 0 ], &response[ response_size ], std::begin( expected_response ), std::end( expected_response ) );\n}\n\ntypedef bluetoe::server<\n    bluetoe::service<\n        bluetoe::service_uuid< 0x8C8B4094, 0x0DE2, 0x499F, 0xA28A, 0x4EED5BC73CAA >,\n        bluetoe::characteristic<\n            bluetoe::characteristic_uuid< 0x8C8B4094, 0x0DE2, 0x499F, 0xA28A, 0x4EED5BC73CAA >,\n            bluetoe::bind_characteristic_value< decltype( test::temperature_value ), &test::temperature_value >,\n            bluetoe::no_write_access\n        >\n    >,\n    bluetoe::service<\n        bluetoe::service_uuid< 0x8C8B4094, 0x0DE2, 0x499F, 0xA28A, 0x4EED5BC73CAA >,\n        bluetoe::characteristic<\n            bluetoe::characteristic_uuid< 0x8C8B4094, 0x0DE2, 0x499F, 0xA28A, 0x4EED5BC73CAA >,\n            bluetoe::bind_characteristic_value< decltype( test::temperature_value ), &test::temperature_value >,\n            bluetoe::no_write_access\n        >\n    >,\n    bluetoe::service<\n        bluetoe::service_uuid16< 0xFF45 >,\n        bluetoe::characteristic<\n            bluetoe::characteristic_uuid< 0x8C8B4094, 0x0DE2, 0x499F, 0xA28A, 0x4EED5BC73CAA >,\n            bluetoe::bind_characteristic_value< decltype( test::temperature_value ), &test::temperature_value >,\n            bluetoe::no_write_access\n        >\n    >\n> server_with_multiple_services;\n\nBOOST_FIXTURE_TEST_CASE( discover_multiple_primary_service_by_service_uuid, test::request_with_reponse< server_with_multiple_services > )\n{\n    l2cap_input({\n        0x06, 0x01, 0x00, 0xFF, 0xFF, 0x00, 0x28,\n        0xAA, 0x3C, 0xC7, 0x5B,     // Service UUID\n        0xED, 0x4E, 0x8A, 0xA2,\n        0x9F, 0x49, 0xE2, 0x0D,\n        0x94, 0x40, 0x8B, 0x8C\n    });\n\n    static const std::uint8_t expected_response[] = {\n        0x07,\n        0x01, 0x00,\n        0x03, 0x00,\n        0x04, 0x00,\n        0x06, 0x00\n    };\n\n    BOOST_CHECK_EQUAL_COLLECTIONS( &response[ 0 ], &response[ response_size ], std::begin( expected_response ), std::end( expected_response ) );\n}\n\nBOOST_FIXTURE_TEST_CASE( discover_multiple_primary_service_by_16_bit_service_uuid, test::request_with_reponse< server_with_multiple_services > )\n{\n    l2cap_input({\n        0x06, 0x01, 0x00, 0xFF, 0xFF, 0x00, 0x28,\n        0x45, 0xFF // Service UUID\n    });\n\n    static const std::uint8_t expected_response[] = {\n        0x07,\n        0x07, 0x00,\n        0x09, 0x00\n    };\n\n    BOOST_CHECK_EQUAL_COLLECTIONS( &response[ 0 ], &response[ response_size ], std::begin( expected_response ), std::end( expected_response ) );\n}\n\n\ntypedef bluetoe::service<\n    bluetoe::service_uuid16< 0xFF45 >,\n    bluetoe::characteristic<\n        bluetoe::characteristic_uuid< 0x8C8B4094, 0x0DE2, 0x499F, 0xA28A, 0x4EED5BC73CAA >,\n        bluetoe::bind_characteristic_value< decltype( test::temperature_value ), &test::temperature_value >,\n        bluetoe::no_write_access\n    >\n> single_service;\n\ntypedef bluetoe::server<\n    single_service,\n    single_service,\n    single_service,\n    single_service,\n    single_service,\n    single_service,\n    single_service,\n    single_service,\n    single_service,\n    single_service,\n    single_service,\n    single_service,\n    single_service,\n    single_service,\n    single_service,\n    single_service,\n    single_service,\n    single_service,\n    single_service,\n    single_service\n> server_with_20_services;\n\nBOOST_FIXTURE_TEST_CASE( discover_multiple_primary_service_by_16_bit_service_uuid_till_buffer_is_full, test::request_with_reponse< server_with_20_services > )\n{\n    l2cap_input({\n        0x06, 0x01, 0x00, 0xFF, 0xFF, 0x00, 0x28,\n        0x45, 0xFF // Service UUID\n    });\n\n    static const std::uint8_t expected_response[] = {\n        0x07,\n        0x01, 0x00,\n        0x03, 0x00,\n        0x04, 0x00,\n        0x06, 0x00,\n        0x07, 0x00,\n        0x09, 0x00,\n        0x0A, 0x00,\n        0x0C, 0x00,\n        0x0D, 0x00,\n        0x0F, 0x00,\n    };\n\n    BOOST_CHECK_EQUAL_COLLECTIONS( &response[ 0 ], &response[ response_size ], std::begin( expected_response ), std::end( expected_response ) );\n}\n\nusing server_with_fixed_handles = bluetoe::server<\n    bluetoe::service<\n        bluetoe::attribute_handle< 0x100 >,\n        bluetoe::service_uuid16< 0xFF45 >,\n        bluetoe::characteristic<\n            bluetoe::characteristic_uuid< 0x8C8B4094, 0x0DE2, 0x499F, 0xA28A, 0x4EED5BC73CAA >,\n            bluetoe::fixed_uint8_value< 0x42 >\n        >\n    >,\n    bluetoe::service<\n        bluetoe::service_uuid16< 0xFF45 >,\n        bluetoe::characteristic<\n            bluetoe::attribute_handles< 0x200, 0x220 >,\n            bluetoe::characteristic_uuid< 0x8C8B4094, 0x0DE2, 0x499F, 0xA28A, 0x4EED5BC73CAA >,\n            bluetoe::fixed_uint8_value< 0x42 >\n        >\n    >,\n    bluetoe::service<\n        bluetoe::service_uuid16< 0xFF45 >,\n        bluetoe::attribute_handle< 0x2244 >,\n        bluetoe::characteristic<\n            bluetoe::characteristic_uuid< 0x8C8B4094, 0x0DE2, 0x499F, 0xA28A, 0x4EED5BC73CAA >,\n            bluetoe::fixed_uint8_value< 0x42 >\n        >\n    >\n>;\n\nBOOST_FIXTURE_TEST_CASE( find_with_fixed_attribute_handles, test::request_with_reponse< server_with_fixed_handles > )\n{\n    l2cap_input({\n        0x06,       // Find By Type Value Request\n        0x01, 0x00, // First requested handle number\n        0xFF, 0xFF, // Last requested handle number\n        0x00, 0x28, // 2 octet UUID to find\n        0x45, 0xFF  // Service UUID\n    });\n\n    expected_result( {\n        0x07,\n        0x00, 0x01,     // 0x100 -\n        0x02, 0x01,     // 0x102\n        0x03, 0x01,     // 0x103 -\n        0x20, 0x02,     // 0x220\n        0x44, 0x22,     // 0x2244 -\n        0x46, 0x22      // 0x2246\n    } );\n}\n\nBOOST_FIXTURE_TEST_CASE( find_in_gap, test::request_with_reponse< server_with_fixed_handles > )\n{\n    l2cap_input({\n        0x06,       // Find By Type Value Request\n        0x00, 0x03, // First requested handle number\n        0x00, 0x04, // Last requested handle number\n        0x00, 0x28, // 2 octet UUID to find\n        0x45, 0xFF  // Service UUID\n    });\n\n    expected_result( {\n        0x01,           // Error Response\n        0x06,           // The request that generated this error response\n        0x00, 0x03,     // The attribute handle that generated this error response\n        0x0A            // Attribute Not Found\n    } );\n}\n\nBOOST_FIXTURE_TEST_CASE( find_exactely_two_groups, test::request_with_reponse< server_with_fixed_handles > )\n{\n    l2cap_input({\n        0x06,       // Find By Type Value Request\n        0x03, 0x01, // First requested handle number\n        0x44, 0x22, // Last requested handle number\n        0x00, 0x28, // 2 octet UUID to find\n        0x45, 0xFF  // Service UUID\n    });\n\n    expected_result( {\n        0x07,\n        0x03, 0x01,     // 0x103 -\n        0x20, 0x02,     // 0x220\n        0x44, 0x22,     // 0x2244 -\n        0x46, 0x22      // 0x2246\n    } );\n}\n\nBOOST_FIXTURE_TEST_CASE( find_exactely_not_the_first_and_last_service, test::request_with_reponse< server_with_fixed_handles > )\n{\n    l2cap_input({\n        0x06,       // Find By Type Value Request\n        0x03, 0x01, // First requested handle number\n        0x43, 0x22, // Last requested handle number\n        0x00, 0x28, // 2 octet UUID to find\n        0x45, 0xFF  // Service UUID\n    });\n\n    expected_result( {\n        0x07,\n        0x03, 0x01,     // 0x103 -\n        0x20, 0x02      // 0x220\n    } );\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "tests/att/find_information_tests.cpp",
    "content": "\n#define BOOST_TEST_MODULE\n#include <boost/test/included/unit_test.hpp>\n\n#include \"test_servers.hpp\"\n\nnamespace {\n    const std::uint8_t request_all_attributes[] = { 0x04, 0x01, 0x00, 0xff, 0xff };\n}\n\nBOOST_AUTO_TEST_SUITE( find_information_errors )\n\n/**\n * @test response with an error if PDU size is to small\n */\nBOOST_FIXTURE_TEST_CASE( pdu_too_small, test::request_with_reponse< test::small_temperature_service > )\n{\n    static const std::uint8_t too_small[] = { 0x04, 0x00, 0x00, 0xff };\n\n    BOOST_CHECK( check_error_response( too_small, 0x04, 0x0000, 0x04 ) );\n}\n\n/**\n * @test response with an error if the starting handle is zero\n */\nBOOST_FIXTURE_TEST_CASE( start_handle_zero, test::request_with_reponse< test::small_temperature_service > )\n{\n    static const std::uint8_t start_zero[] = { 0x04, 0x00, 0x00, 0xff, 0xff };\n\n    BOOST_CHECK( check_error_response( start_zero, 0x04, 0x0000, 0x01 ) );\n}\n\n/**\n * @test response with an invalid handle, if starting handle is larger than ending handle\n */\nBOOST_FIXTURE_TEST_CASE( start_handle_larger_than_ending, test::request_with_reponse< test::small_temperature_service > )\n{\n    static const std::uint8_t larger_than[] = { 0x04, 0x06, 0x00, 0x05, 0x00 };\n\n    BOOST_CHECK( check_error_response( larger_than, 0x04, 0x0006, 0x01 ) );\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE( find_small_temperature_service_valid_requests )\n\nBOOST_FIXTURE_TEST_CASE( request_out_of_range, test::request_with_reponse< test::small_temperature_service > )\n{\n    static const std::uint8_t request[] = { 0x04, 0x04, 0x00, 0xff, 0xff };\n    BOOST_CHECK( check_error_response( request, 0x04, 0x0004, 0x0A ) );\n}\n\nBOOST_FIXTURE_TEST_CASE( correct_opcode, test::request_with_reponse< test::small_temperature_service > )\n{\n    l2cap_input( request_all_attributes );\n\n    BOOST_REQUIRE_GT( response_size, 0u );\n    BOOST_CHECK_EQUAL( response[ 0 ], 0x05 );\n}\n\nBOOST_FIXTURE_TEST_CASE( correct_list_of_16bit_uuids, test::request_with_reponse< test::small_temperature_service > )\n{\n    l2cap_input( request_all_attributes );\n\n    expected_result({\n        0x05, 0x01,             // response opcode and format\n        0x01, 0x00, 0x00, 0x28, // service definition\n        0x02, 0x00, 0x03, 0x28  // Characteristic Declaration\n    });\n}\n\nBOOST_FIXTURE_TEST_CASE( correct_list_of_128bit_uuids, test::request_with_reponse< test::small_temperature_service > )\n{\n    static const std::uint8_t request_value_attribute[] = { 0x04, 0x03, 0x00, 0x03, 0x00 };\n    l2cap_input( request_value_attribute );\n\n    expected_result({\n        0x05, 0x02,             // response opcode and format\n        0x03, 0x00,             // handle\n        0xAA, 0x3C, 0xC7, 0x5B,\n        0xED, 0x4E, 0x8A, 0xA2,\n        0x9F, 0x49, 0xE2, 0x0D,\n        0x94, 0x40, 0x8B, 0x8C\n    });\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE( more_than_one_characteristics )\n\nBOOST_FIXTURE_TEST_CASE( as_long_as_mtu_size_is_large_enough_all_16bit_uuids_will_be_served, test::request_with_reponse< test::three_apes_service > )\n{\n    l2cap_input( request_all_attributes );\n\n    expected_result({\n        0x05, 0x01,             // response opcode and format\n        0x01, 0x00, 0x00, 0x28, // service definition\n        0x02, 0x00, 0x03, 0x28, // Characteristic Declaration\n        0x04, 0x00, 0x03, 0x28,\n        0x06, 0x00, 0x03, 0x28\n    });\n}\n\nBOOST_FIXTURE_TEST_CASE( response_includes_the_starting_and_ending_handle, test::request_with_reponse< test::three_apes_service > )\n{\n    const std::uint8_t request[] = { 0x04, 0x02, 0x00, 0x04, 0x00 };\n    l2cap_input( request );\n\n    expected_result({\n        0x05, 0x01,\n        0x02, 0x00, 0x03, 0x28,\n        0x04, 0x00, 0x03, 0x28\n    });\n}\n\ntypedef test::request_with_reponse< test::three_apes_service, 56 > request_with_reponse_three_apes_service_56;\n\nBOOST_FIXTURE_TEST_CASE( response_will_contain_only_128bit_uuids_if_the_first_one_is_a_128_bituuid, request_with_reponse_three_apes_service_56 )\n{\n    const std::uint8_t request[] = { 0x04, 0x03, 0x00, 0xff, 0xff };\n    l2cap_input( request );\n\n    expected_result({\n        0x05, 0x02,\n        0x03, 0x00,\n        0xAA, 0x3C, 0xC7, 0x5B,\n        0xED, 0x4E, 0x8A, 0xA2,\n        0x9F, 0x49, 0xE2, 0x0D,\n        0x94, 0x40, 0x8B, 0x8C,\n        0x05, 0x00,\n        0xAB, 0x3C, 0xC7, 0x5B,\n        0xED, 0x4E, 0x8A, 0xA2,\n        0x9F, 0x49, 0xE2, 0x0D,\n        0x94, 0x40, 0x8B, 0x8C,\n        0x07, 0x00,\n        0xAC, 0x3C, 0xC7, 0x5B,\n        0xED, 0x4E, 0x8A, 0xA2,\n        0x9F, 0x49, 0xE2, 0x0D,\n        0x94, 0x40, 0x8B, 0x8C\n    });\n}\n\ntypedef test::request_with_reponse< test::three_apes_service, 55 > request_with_reponse_three_apes_service_55;\nBOOST_FIXTURE_TEST_CASE( response_will_contain_one_whole_tuples, request_with_reponse_three_apes_service_55 )\n{\n    const std::uint8_t request[] = { 0x04, 0x03, 0x00, 0xff, 0xff };\n    l2cap_input( request );\n\n    expected_result({\n        0x05, 0x02,\n        0x03, 0x00,\n        0xAA, 0x3C, 0xC7, 0x5B,\n        0xED, 0x4E, 0x8A, 0xA2,\n        0x9F, 0x49, 0xE2, 0x0D,\n        0x94, 0x40, 0x8B, 0x8C,\n        0x05, 0x00,\n        0xAB, 0x3C, 0xC7, 0x5B,\n        0xED, 0x4E, 0x8A, 0xA2,\n        0x9F, 0x49, 0xE2, 0x0D,\n        0x94, 0x40, 0x8B, 0x8C\n    });\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE( server_with_fixed_attributes )\n\n    static const char char_name_foo[] = \"Foo\";\n    static const char char_name_bar[] = \"Bar\";\n    static const char char_name_baz[] = \"Baz\";\n    static const std::uint8_t descriptor_data[] = { 0x08, 0x15 };\n\n    using server_with_additional_descriptors = bluetoe::server<\n        bluetoe::no_gap_service_for_gatt_servers,\n        bluetoe::service<\n            bluetoe::attribute_handle< 0x020 >,\n            bluetoe::service_uuid16< 0x0815 >,\n\n            // Characteristic with CCCD and Characteristic User Description without fixed CCCD\n            bluetoe::characteristic<\n                bluetoe::characteristic_uuid16< 0x1516 >,\n                bluetoe::attribute_handles< 0x50, 0x52 >,\n                bluetoe::fixed_uint8_value< 0x42 >,\n                bluetoe::characteristic_name< char_name_foo >,\n                bluetoe::notify\n            >,\n            // Characteristic with CCCD and Characteristic User Description and user descriptor with fixed CCCD\n            bluetoe::characteristic<\n                bluetoe::characteristic_uuid16< 0x1517 >,\n                bluetoe::attribute_handles< 0x60, 0x62, 0x64 >,\n                bluetoe::fixed_uint8_value< 0x43 >,\n                bluetoe::characteristic_name< char_name_bar >,\n                bluetoe::descriptor< 0x1722, descriptor_data, sizeof( descriptor_data ) >,\n                bluetoe::notify\n            >,\n            // No descriptors, no fixup\n            bluetoe::characteristic<\n                bluetoe::characteristic_uuid16< 0x1518 >,\n                bluetoe::fixed_uint8_value< 0x44 >\n            >,\n            // Characteristic Characteristic User Description without fixed CCCD\n            bluetoe::characteristic<\n                bluetoe::characteristic_uuid16< 0x1519 >,\n                bluetoe::attribute_handles< 0x70, 0x80 >,\n                bluetoe::fixed_uint8_value< 0x45 >,\n                bluetoe::characteristic_name< char_name_baz >\n            >\n        >\n    >;\n\n    using fixture = test::request_with_reponse< server_with_additional_descriptors, 200 >;\n    BOOST_FIXTURE_TEST_CASE( find_all, fixture )\n    {\n        l2cap_input({\n            0x04,           // Find Information Request\n            0x01, 0x00,     // 0x0001\n            0xff, 0xff      // 0xffff\n        });\n\n        expected_result({\n            0x05, 0x01,\n            // first characteristic\n            0x20, 0x00,     // 0x0020 ->\n            0x00, 0x28,     // 0x2800\n            0x50, 0x00,     // 0x0050 ->\n            0x03, 0x28,     // 0x2803 Characteristic Declaration\n            0x52, 0x00,     // 0x0052 ->\n            0x16, 0x15,     // 0x1516\n            0x53, 0x00,     // 0x0053 ->\n            0x02, 0x29,     // 0x2902 «Client Characteristic Configuration»\n            0x54, 0x00,     // 0x0054 ->\n            0x01, 0x29,     // 0x2901 «Characteristic User Description»\n            // second characteristic\n            0x60, 0x00,     // 0x0060 ->\n            0x03, 0x28,     // 0x2803 Characteristic Declaration\n            0x62, 0x00,     // 0x0062 ->\n            0x17, 0x15,     // 0x1517\n            0x64, 0x00,     // 0x0064 ->\n            0x02, 0x29,     // 0x2902 «Client Characteristic Configuration»\n            0x65, 0x00,     // 0x0065 ->\n            0x01, 0x29,     // 0x2901 «Characteristic User Description»\n            0x66, 0x00,     // 0x0066 ->\n            0x22, 0x17,     // 0x1722\n            // third characteristic\n            0x67, 0x00,     // 0x0067 ->\n            0x03, 0x28,     // 0x2803 Characteristic Declaration\n            0x68, 0x00,     // 0x0068 ->\n            0x18, 0x15,     // 0x1518\n            // forth characteristic\n            0x70, 0x00,     // 0x0070 ->\n            0x03, 0x28,     // 0x2803 Characteristic Declaration\n            0x80, 0x00,     // 0x0080 ->\n            0x19, 0x15,     // 0x1519\n            0x81, 0x00,     // 0x0065 ->\n            0x01, 0x29,     // 0x2901 «Characteristic User Description»\n\n\n        });\n    }\n\nBOOST_AUTO_TEST_SUITE_END()\n\n"
  },
  {
    "path": "tests/att/find_notification_data_tests.cpp",
    "content": "#define BOOST_TEST_MODULE\n#include <boost/test/included/unit_test.hpp>\n\n#include <bluetoe/server.hpp>\n#include <bluetoe/attribute.hpp>\n#include <bluetoe/outgoing_priority.hpp>\n\n/*\n * A notification index is a key to a characteristic that is configured to allow notifications or indications.\n * higher_outgoing_priority and lower_outgoing_priority lead to none linear distribution of the notification indexes over\n * all characeteristics. The characteristics are stable sorted by priority and then numerated (started by 0).\n */\n\nconst std::uint8_t value_Aa = 0xAa;\nconst std::uint8_t value_Ab = 0xAb;\nconst std::uint8_t value_Ac = 0xAc;\n\nconst std::uint8_t value_Ba = 0xBa;\nconst std::uint8_t value_Bb = 0xBb;\nconst std::uint8_t value_Bc = 0xBc;\n\nusing A = bluetoe::service_uuid16< 0x1234 >;\n\nusing A_a = bluetoe::characteristic_uuid16< 0xFF00 >;\nusing A_b = bluetoe::characteristic_uuid16< 0xFF01 >;\nusing A_c = bluetoe::characteristic_uuid16< 0xFF02 >;\n\nusing B = bluetoe::service_uuid16< 0x1235 >;\n\nusing B_a = bluetoe::characteristic_uuid16< 0xFF10 >;\nusing B_b = bluetoe::characteristic_uuid16< 0xFF11 >;\nusing B_c = bluetoe::characteristic_uuid16< 0xFF12 >;\n\ntemplate < class Server >\nusing connection_t = typename Server::template channel_data_t< bluetoe::details::link_state_no_security >;\n\ntemplate < class Server >\nstd::uint8_t read_value( std::size_t notification_index )\n{\n    // opcode + handle + 1 octed value (the std::uint8_t's from above)\n    static constexpr std::size_t value_notification_pdu_min_size = 1 + 2 + 1;\n\n    connection_t< Server > data_per_connection;\n    Server server;\n\n    // subscribe the characteristic:\n    data_per_connection.client_configurations().flags( notification_index, 1 );\n    data_per_connection.queue_notification( notification_index );\n\n    std::uint8_t out_buffer[ value_notification_pdu_min_size + 100 ];\n    std::size_t  out_size = sizeof( out_buffer );\n\n    server.l2cap_output( out_buffer, out_size, data_per_connection );\n\n    BOOST_CHECK_EQUAL( value_notification_pdu_min_size, out_size );\n\n    return out_buffer[ value_notification_pdu_min_size - 1 ];\n}\n\ntemplate < class UUID, const std::uint8_t* Value >\nusing characteristic =\n    bluetoe::characteristic<\n        UUID,\n        bluetoe::bind_characteristic_value< const std::uint8_t, Value >,\n        bluetoe::notify\n    >;\n\ntemplate < class UUID, const std::uint8_t* Value >\nusing characteristic_without_cccd =\n    bluetoe::characteristic<\n        UUID,\n        bluetoe::bind_characteristic_value< const std::uint8_t, Value >\n    >;\n\nBOOST_AUTO_TEST_CASE( all_default_prio )\n{\n    using server = bluetoe::server<\n        bluetoe::service<\n            A,\n            characteristic< A_a, &value_Aa >,\n            characteristic< A_b, &value_Ab >\n        >,\n        bluetoe::service<\n            B,\n            characteristic< B_a, &value_Ba >,\n            characteristic< B_b, &value_Bb >\n        >\n    >;\n\n    BOOST_CHECK_EQUAL( read_value< server >( 0 ), 0xAa );\n    BOOST_CHECK_EQUAL( read_value< server >( 1 ), 0xAb );\n    BOOST_CHECK_EQUAL( read_value< server >( 2 ), 0xBa );\n    BOOST_CHECK_EQUAL( read_value< server >( 3 ), 0xBb );\n}\n\n/*\n     Service:  | A       | B\n     ------------------------------\n     highest   |         | a, b\n     lowest    | a, c    |\n*/\n\nBOOST_AUTO_TEST_CASE( service_with_higher_priority )\n{\n    using server = bluetoe::server<\n        bluetoe::service<\n            A,\n            characteristic< A_a, &value_Aa >,\n            characteristic< A_b, &value_Ab >\n        >,\n        bluetoe::service<\n            B,\n            characteristic< B_a, &value_Ba >,\n            characteristic< B_b, &value_Bb >\n        >,\n        bluetoe::higher_outgoing_priority< B >\n    >;\n\n    BOOST_CHECK_EQUAL( read_value< server >( 0 ), 0xBa );\n    BOOST_CHECK_EQUAL( read_value< server >( 1 ), 0xBb );\n    BOOST_CHECK_EQUAL( read_value< server >( 2 ), 0xAa );\n    BOOST_CHECK_EQUAL( read_value< server >( 3 ), 0xAb );\n}\n\n/*\n     Service:  | A       | B\n     ------------------------------\n     highest   | a       | a\n               | b       | b\n     lowest    | c       | c\n*/\nBOOST_AUTO_TEST_CASE( two_services_with_similar_characteristic_priorities )\n{\n    using server = bluetoe::server<\n        bluetoe::service<\n            A,\n            characteristic< A_a, &value_Aa >,\n            characteristic< A_b, &value_Ab >,\n            characteristic< A_c, &value_Ac >,\n            bluetoe::higher_outgoing_priority< A_a, A_b >\n        >,\n        bluetoe::service<\n            B,\n            characteristic< B_a, &value_Ba >,\n            characteristic< B_b, &value_Bb >,\n            characteristic< B_c, &value_Bc >,\n            bluetoe::higher_outgoing_priority< B_a, B_b >\n        >\n    >;\n\n    BOOST_CHECK_EQUAL( read_value< server >( 0 ), 0xAa );\n    BOOST_CHECK_EQUAL( read_value< server >( 1 ), 0xBa );\n    BOOST_CHECK_EQUAL( read_value< server >( 2 ), 0xAb );\n    BOOST_CHECK_EQUAL( read_value< server >( 3 ), 0xBb );\n    BOOST_CHECK_EQUAL( read_value< server >( 4 ), 0xAc );\n    BOOST_CHECK_EQUAL( read_value< server >( 5 ), 0xBc );\n}\n\n/*\n     Service:  | A       | B\n     ------------------------------\n     highest   |         | c\n               |         | a, b\n               | c       |\n               | b       |\n     lowest    | a       |\n\n*/\nBOOST_AUTO_TEST_CASE( two_services_with_similar_characteristic_priorities_but_different_service_priority )\n{\n    using server = bluetoe::server<\n        bluetoe::service<\n            A,\n            characteristic< A_a, &value_Aa >,\n            characteristic< A_b, &value_Ab >,\n            characteristic< A_c, &value_Ac >,\n            bluetoe::higher_outgoing_priority< A_c, A_b >\n        >,\n        bluetoe::service<\n            B,\n            characteristic< B_a, &value_Ba >,\n            characteristic< B_b, &value_Bb >,\n            characteristic< B_c, &value_Bc >,\n            bluetoe::higher_outgoing_priority< B_c >\n        >,\n        bluetoe::higher_outgoing_priority< B >\n    >;\n\n    BOOST_CHECK_EQUAL( read_value< server >( 0 ), 0xBc );\n    BOOST_CHECK_EQUAL( read_value< server >( 1 ), 0xBa );\n    BOOST_CHECK_EQUAL( read_value< server >( 2 ), 0xBb );\n    BOOST_CHECK_EQUAL( read_value< server >( 3 ), 0xAc );\n    BOOST_CHECK_EQUAL( read_value< server >( 4 ), 0xAb );\n    BOOST_CHECK_EQUAL( read_value< server >( 5 ), 0xAa );\n}\n\ntemplate < int I >\nusing int_c = std::integral_constant< std::size_t, I >;\n\nBOOST_AUTO_TEST_CASE( default_cccd_indices )\n{\n    using server = bluetoe::server<\n        bluetoe::service<\n            A,\n            characteristic< A_a, &value_Aa >,\n            characteristic< A_b, &value_Ab >,\n            characteristic< A_c, &value_Ac >\n        >,\n        bluetoe::service<\n            B,\n            characteristic< B_a, &value_Ba >,\n            characteristic< B_b, &value_Bb >,\n            characteristic< B_c, &value_Bc >\n        >\n    >;\n\n    BOOST_CHECK( (\n        std::is_same<\n            server::cccd_indices,\n            std::tuple< int_c< 0 >, int_c< 1 >, int_c< 2 >, int_c< 3 >, int_c< 4 >, int_c< 5 > > >::value\n    ) );\n\n}\n\n/*\n     Service:  | A       | B\n     ------------------------------\n     highest   |         | c\n               |         | a\n               | c       |\n               | b       |\n     lowest    | a       |\n\n*/\nBOOST_AUTO_TEST_CASE( cccd_indices_with_some_priorities )\n{\n    using server = bluetoe::server<\n        bluetoe::service<\n            A,\n            characteristic< A_a, &value_Aa >,\n            characteristic< A_b, &value_Ab >,\n            characteristic< A_c, &value_Ac >,\n            bluetoe::higher_outgoing_priority< A_c, A_b >\n        >,\n        bluetoe::service<\n            B,\n            characteristic< B_a, &value_Ba >,\n            characteristic_without_cccd< B_b, &value_Bb >,\n            characteristic< B_c, &value_Bc >,\n            bluetoe::higher_outgoing_priority< B_c >\n        >,\n        bluetoe::higher_outgoing_priority< B >\n    >;\n\n    BOOST_CHECK( (\n        std::is_same<\n            server::cccd_indices,\n            std::tuple< int_c< 4 >, int_c< 3 >, int_c< 2 >, int_c< 1 >, int_c< 0 > > >::value\n    ) );\n}\n\nBOOST_AUTO_TEST_CASE( multiple_characteristics_with_same_uuid )\n{\n    using server = bluetoe::server<\n        bluetoe::service<\n            A,\n            characteristic< A_a, &value_Aa >,\n            characteristic_without_cccd< A_a, &value_Ab >,\n            characteristic_without_cccd< A_a, &value_Ac >\n        >\n    >;\n\n    BOOST_CHECK( (\n        std::is_same<\n            server::cccd_indices,\n            std::tuple< int_c< 0 > > >::value\n    ) );\n}\n"
  },
  {
    "path": "tests/att/indication_tests.cpp",
    "content": "#define BOOST_TEST_MODULE\n#include <boost/test/included/unit_test.hpp>\n\n#include <bluetoe/server.hpp>\n\n#include \"test_servers.hpp\"\n#include \"attribute_io.hpp\"\n\nstd::uint8_t value = 0x42;\n\nusing simple_server = bluetoe::server<\n    bluetoe::service<\n        bluetoe::service_uuid16< 0x8C8B >,\n        bluetoe::characteristic<\n            bluetoe::characteristic_uuid16< 0x8C8B >,\n            bluetoe::bind_characteristic_value< std::uint8_t, &value >,\n            bluetoe::indicate\n        >\n    >\n>;\n\nBOOST_AUTO_TEST_SUITE( indications_by_value )\n\n    BOOST_FIXTURE_TEST_CASE( indication_adds_a_client_configuration, test::request_with_reponse< simple_server > )\n    {\n        BOOST_REQUIRE_EQUAL( int{ number_of_client_configs }, 1 );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( l2cap_layer_gets_notified, test::request_with_reponse< simple_server > )\n    {\n        indicate( value );\n\n        BOOST_CHECK( notification.valid() );\n        BOOST_CHECK_EQUAL( notification.attribute_table_index(), 2u );\n        BOOST_CHECK_EQUAL( notification_type, bluetoe::details::notification_type::indication );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( if_client_configuration_is_not_enabled_not_output, test::request_with_reponse< simple_server > )\n    {\n        channel_data_t< bluetoe::details::link_state_no_security > client_configuration;\n        client_configuration.queue_indication( 0 );\n\n        std::size_t size = client_configuration.negotiated_mtu();\n        l2cap_output( begin(), size, client_configuration );\n\n        BOOST_CHECK_EQUAL( size, 0u );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( output_if_enables, test::request_with_reponse< simple_server > )\n    {\n        channel_data_t< bluetoe::details::link_state > client_configuration;\n        client_configuration.queue_indication( 0 );\n        client_configuration.client_configurations().flags( 0, 2 ); // 2 == indications\n\n        std::size_t size = client_configuration.negotiated_mtu();\n        l2cap_output( begin(), size, client_configuration );\n\n        static const std::uint8_t expected_output[] = { 0x1D, 0x03, 0x00, 0x42 };\n        BOOST_CHECK_EQUAL( size, sizeof( expected_output ) );\n        BOOST_CHECK_EQUAL_COLLECTIONS( begin(), begin() + size, std::begin( expected_output ), std::end( expected_output ) );\n    }\n\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE( indications_by_uuid )\n\n    static const std::uint16_t value1 = 0x1111;\n    static const std::uint16_t value2 = 0x2222;\n    static const std::uint16_t value3 = 0x3333;\n    static const std::uint16_t dummy  = 0x4444;\n\n    typedef bluetoe::server<\n        bluetoe::service<\n            bluetoe::service_uuid16< 0x8C8B >,\n            bluetoe::characteristic<\n                bluetoe::characteristic_uuid16< 0x1111 >,\n                bluetoe::bind_characteristic_value< decltype( value1 ), &value1 >,\n                bluetoe::notify\n            >,\n            bluetoe::characteristic<\n                bluetoe::characteristic_uuid16< 0xffff >,\n                bluetoe::bind_characteristic_value< decltype( dummy ), &dummy >\n            >,\n            bluetoe::characteristic<\n                bluetoe::characteristic_uuid16< 0x2222 >,\n                bluetoe::bind_characteristic_value< decltype( value2 ), &value2 >,\n                bluetoe::notify,\n                bluetoe::indicate\n            >\n        >,\n        bluetoe::service<\n            bluetoe::service_uuid16< 0x8C8C >,\n            bluetoe::characteristic<\n                bluetoe::characteristic_uuid16< 0xffff >,\n                bluetoe::bind_characteristic_value< decltype( dummy ), &dummy >\n            >,\n            bluetoe::characteristic<\n                bluetoe::characteristic_uuid16< 0x3333 >,\n                bluetoe::bind_characteristic_value< decltype( value3 ), &value3 >,\n                bluetoe::indicate\n            >\n        >\n    > server;\n\n    BOOST_FIXTURE_TEST_CASE( notify_first_16bit_uuid, test::request_with_reponse< server > )\n    {\n        indicate< bluetoe::characteristic_uuid16< 0x2222 > >();\n\n        BOOST_REQUIRE( notification.valid() );\n        BOOST_CHECK_EQUAL( notification.attribute_table_index(), 7u );\n        BOOST_CHECK_EQUAL( notification.client_characteristic_configuration_index(), 1u );\n        BOOST_CHECK_EQUAL( notification_type, bluetoe::details::notification_type::indication );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( notify_second_16bit_uuid, test::request_with_reponse< server > )\n    {\n        indicate< bluetoe::characteristic_uuid16< 0x3333 > >();\n\n        BOOST_REQUIRE( notification.valid() );\n        BOOST_CHECK_EQUAL( notification.attribute_table_index(), 13u );\n        BOOST_CHECK_EQUAL( notification.client_characteristic_configuration_index(), 2u );\n        BOOST_CHECK_EQUAL( notification_type, bluetoe::details::notification_type::indication );\n    }\n\n    // This test should not compile\n    /*\n    BOOST_FIXTURE_TEST_CASE( indicating_not_configured_will_result_in_compiletime_error, test::request_with_reponse< server > )\n    {\n        indicate< bluetoe::characteristic_uuid16< 0x1111 > >();\n    }\n    */\n\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE( confirmation )\n\n    BOOST_FIXTURE_TEST_CASE( confirmation_is_forwared_to_the_link_layer, test::request_with_reponse< simple_server > )\n    {\n        l2cap_input( { 0x1E } );\n\n        BOOST_CHECK( !notification.valid() );\n        BOOST_CHECK_EQUAL( notification_type, bluetoe::details::notification_type::confirmation );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( no_response_to_a_confirmation, test::request_with_reponse< simple_server > )\n    {\n        l2cap_input( { 0x1E } );\n\n        BOOST_CHECK_EQUAL( response_size, 0u );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( broken_pdu, test::request_with_reponse< simple_server > )\n    {\n        check_error_response(\n            { 0x1E, 0x00 },\n            0x1E, 0x0000, 0x04 );\n    }\n\nBOOST_AUTO_TEST_SUITE_END()\n\nusing server_with_notify_on_subscription = bluetoe::server<\n    bluetoe::service<\n        bluetoe::service_uuid16< 0x1234 >,\n\n        // Handle of CCCD is: 0x0004\n        bluetoe::characteristic<\n            bluetoe::bind_characteristic_value< std::uint8_t, &value >,\n            bluetoe::characteristic_uuid16< 0x0001 >,\n            bluetoe::notify,\n            bluetoe::notify_on_subscription\n        >,\n\n        // Handle of CCCD is: 0x2000\n        bluetoe::characteristic<\n            bluetoe::bind_characteristic_value< std::uint8_t, &value >,\n            bluetoe::attribute_handles< 0x1000, 0x2000, 0x3000 >,\n            bluetoe::characteristic_uuid16< 0x0002 >,\n            bluetoe::indicate,\n            bluetoe::indicate_on_subscription\n        >\n    >\n>;\n\nBOOST_AUTO_TEST_SUITE( notify_on_subscription )\n\n    BOOST_FIXTURE_TEST_CASE( test_notification, test::request_with_reponse< server_with_notify_on_subscription > )\n    {\n        l2cap_input( { 0x12, 0x04, 0x00, 0x01, 0x00 } );\n\n        BOOST_CHECK_EQUAL( connection.client_configurations().flags( 0 ), 0x0001 );\n\n        BOOST_REQUIRE( notification.valid() );\n        BOOST_CHECK_EQUAL( notification.attribute_table_index(), 2u );\n        BOOST_CHECK( notification_type == bluetoe::details::notification_type::notification );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( test_indication, test::request_with_reponse< server_with_notify_on_subscription > )\n    {\n        l2cap_input( { 0x12, 0x00, 0x30, 0x02, 0x00 } );\n\n        BOOST_CHECK_EQUAL( connection.client_configurations().flags( 1 ), 0x0002 );\n\n        BOOST_REQUIRE( notification.valid() );\n        BOOST_CHECK_EQUAL( notification.attribute_table_index(), 5u );\n        BOOST_CHECK( notification_type == bluetoe::details::notification_type::indication );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( no_cb_called_when_not_configured, test::request_with_reponse< simple_server > )\n    {\n        l2cap_input( { 0x12, 0x04, 0x00, 0x01, 0x00 } );\n\n        BOOST_CHECK_EQUAL( connection.client_configurations().flags( 0 ), 0x0001 );\n        BOOST_CHECK( !notification.valid() );\n    }\n\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE( access_error )\n\n    std::uint8_t error( std::size_t, std::uint8_t*, std::size_t& )\n    {\n        // something != bluetoe::error_codes::success;\n        return bluetoe::error_codes::invalid_pdu;\n    }\n\n    using server = bluetoe::server<\n        bluetoe::service<\n            bluetoe::service_uuid16< 0x1234 >,\n            bluetoe::characteristic<\n                bluetoe::free_read_handler< &error >,\n                bluetoe::characteristic_uuid16< 0x0001 >,\n                bluetoe::indicate\n            >\n        >\n    >;\n\n    BOOST_FIXTURE_TEST_CASE( read_error, test::request_with_reponse< server > )\n    {\n        l2cap_input( { 0x12, 0x04, 0x00, 0x02, 0x00 } );\n\n        std::uint8_t output_buffer[ 50 ];\n        std::size_t  output_size = sizeof( output_buffer );\n\n        l2cap_output( output_buffer, output_size, connection );\n\n        BOOST_CHECK_EQUAL( output_size, 0u );\n    }\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "tests/att/mtu_exchange_tests.cpp",
    "content": "\n#define BOOST_TEST_MODULE\n#include <boost/test/included/unit_test.hpp>\n\n#include \"test_servers.hpp\"\n\nBOOST_FIXTURE_TEST_CASE( pdu_to_small, test::small_temperature_service_with_response<> )\n{\n    BOOST_CHECK( check_error_response( { 0x02, 0x50 }, 0x02, 0x0000, 0x04 ) );\n}\n\nBOOST_FIXTURE_TEST_CASE( pdu_to_large, test::small_temperature_service_with_response<> )\n{\n    BOOST_CHECK( check_error_response( { 0x02, 0x50, 0x00, 0x01 }, 0x02, 0x0000, 0x04 ) );\n}\n\nBOOST_FIXTURE_TEST_CASE( mtu_to_small, test::small_temperature_service_with_response<> )\n{\n    BOOST_CHECK( check_error_response( { 0x02, 0x16, 0x00 }, 0x02, 0x0000, 0x04 ) );\n}\n\nBOOST_FIXTURE_TEST_CASE( mtu_equal_default_mtu, test::small_temperature_service_with_response<> )\n{\n    l2cap_input( { 0x02, 0x17, 0x00 } );\n    expected_result( { 0x03, 0x17, 0x00 } );\n    BOOST_CHECK_EQUAL( connection.negotiated_mtu(), 0x0017 );\n}\n\nBOOST_FIXTURE_TEST_CASE( client_mtu_is_smaller, test::small_temperature_service_with_response< 0x100 > )\n{\n    l2cap_input( { 0x02, 0x22, 0x00 } );\n    expected_result( { 0x03, 0x00, 0x01 } );\n    BOOST_CHECK_EQUAL( connection.negotiated_mtu(), 0x0022 );\n}\n\nBOOST_FIXTURE_TEST_CASE( client_mtu_is_larger, test::small_temperature_service_with_response< 0x100 > )\n{\n    l2cap_input( { 0x02, 0x11, 0x11 } );\n    expected_result( { 0x03, 0x00, 0x01 } );\n    BOOST_CHECK_EQUAL( connection.negotiated_mtu(), 0x100 );\n}\n\nchar large_data[ 30 ];\n\ntypedef bluetoe::server<\n    bluetoe::service<\n        bluetoe::service_uuid< 0x8C8B4094, 0x0DE2, 0x499F, 0xA28A, 0x4EED5BC73CA9 >,\n        bluetoe::characteristic<\n            bluetoe::characteristic_uuid< 0x8C8B4094, 0x0DE2, 0x499F, 0xA28A, 0x4EED5BC73CAA >,\n            bluetoe::bind_characteristic_value< decltype( large_data ), &large_data >\n        >\n    >\n> large_data_service;\n\ntypedef test::request_with_reponse< large_data_service, 30 > request_with_reponse_large_data_service_30;\n\nBOOST_FIXTURE_TEST_CASE( server_honors_negotiated_mtu, request_with_reponse_large_data_service_30 )\n{\n    l2cap_input( { 0x02, 0x1D, 0x00 } );\n    BOOST_CHECK_EQUAL( connection.negotiated_mtu(), 29 );\n\n    // now read the characteristic value attribute\n    l2cap_input( { 0x0A, 0x03, 0x00 } );\n    BOOST_CHECK_EQUAL( response_size, 29u );\n}\n"
  },
  {
    "path": "tests/att/notification_tests.cpp",
    "content": "#define BOOST_TEST_MODULE\n#include <boost/test/included/unit_test.hpp>\n\n#include <bluetoe/notification_queue.hpp>\n\n#include \"test_servers.hpp\"\n#include \"attribute_io.hpp\"\n\nBOOST_AUTO_TEST_SUITE( notifications_by_value )\n\n    std::uint8_t value = 0;\n\n    typedef bluetoe::server<\n        bluetoe::service<\n            bluetoe::service_uuid16< 0x8C8B >,\n            bluetoe::characteristic<\n                bluetoe::characteristic_uuid16< 0x8C8B >,\n                bluetoe::bind_characteristic_value< std::uint8_t, &value >,\n                bluetoe::notify\n            >\n        >\n    > simple_server;\n\n    BOOST_FIXTURE_TEST_CASE( l2cap_layer_gets_notified, test::request_with_reponse< simple_server > )\n    {\n        notify( value );\n\n        BOOST_CHECK( notification.valid() );\n        BOOST_CHECK_EQUAL( notification.attribute_table_index(), 2u );\n        BOOST_CHECK_EQUAL( notification_type, bluetoe::details::notification_type::notification );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( no_output_when_notification_not_enabled, test::request_with_reponse< simple_server > )\n    {\n        expected_output( value, {} );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( notification_if_enabled, test::request_with_reponse< simple_server > )\n    {\n        l2cap_input( { 0x12, 0x04, 0x00, 0x01, 0x00 } );\n        expected_result( { 0x13 } );\n\n        value = 0xab;\n        connection.queue_notification( 0 );\n        expected_output( value, { 0x1B, 0x03, 0x00, 0xab } );\n    }\n\n    std::uint8_t large_buffer[] = {\n        0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,\n        0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19,\n        0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29\n    };\n\n    typedef bluetoe::server<\n        bluetoe::service<\n            bluetoe::service_uuid16< 0x8C8B >,\n            bluetoe::characteristic<\n                bluetoe::characteristic_uuid16< 0x8C8B >,\n                bluetoe::bind_characteristic_value< decltype( large_buffer ), &large_buffer >,\n                bluetoe::notify\n            >\n        >\n    > large_value_notify_server;\n\n    BOOST_FIXTURE_TEST_CASE( notification_data_is_clipped_to_mtu_size_23, test::request_with_reponse< large_value_notify_server > )\n    {\n        l2cap_input( { 0x12, 0x04, 0x00, 0x01, 0x00 } );\n        expected_result( { 0x13 } );\n\n        connection.queue_notification( 0 );\n        expected_output( large_buffer, {\n            0x1B, 0x03, 0x00,\n            0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,\n            0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19\n        } );\n    }\n\n    std::uint8_t value_a1 = 1;\n    std::uint8_t value_a2 = 2;\n    std::uint8_t value_b1 = 3;\n    std::uint8_t value_c1 = 4;\n    std::uint8_t value_c2 = 5;\n\n    typedef bluetoe::server<\n        bluetoe::service<\n            bluetoe::service_uuid16< 0x8C8B >,\n            bluetoe::characteristic<\n                bluetoe::characteristic_uuid16< 0x8C8B >,\n                bluetoe::bind_characteristic_value< std::uint8_t, &value_a1 >,\n                bluetoe::notify\n            >,\n            bluetoe::characteristic<\n                bluetoe::characteristic_uuid16< 0x8C8C >,\n                bluetoe::bind_characteristic_value< std::uint8_t, &value_a2 >,\n                bluetoe::notify\n            >\n        >,\n        bluetoe::service<\n            bluetoe::service_uuid16< 0x8C8C >,\n            bluetoe::characteristic<\n                bluetoe::characteristic_uuid16< 0x8C8D >,\n                bluetoe::bind_characteristic_value< std::uint8_t, &value_b1 >,\n                bluetoe::notify\n            >\n        >,\n        bluetoe::service<\n            bluetoe::service_uuid16< 0x8C8D >,\n            bluetoe::characteristic<\n                bluetoe::characteristic_uuid16< 0x8C8E >,\n                bluetoe::bind_characteristic_value< std::uint8_t, &value_c1 >,\n                bluetoe::notify\n            >,\n            bluetoe::characteristic<\n                bluetoe::characteristic_uuid16< 0x8C8F >,\n                bluetoe::bind_characteristic_value< std::uint8_t, &value_c2 >,\n                bluetoe::notify\n            >\n        >\n    > server_with_multiple_char;\n\n    BOOST_FIXTURE_TEST_CASE( all_values_notifable, test::request_with_reponse< server_with_multiple_char > )\n    {\n        notify( value_a1 );\n        notify( value_a2 );\n        notify( value_b1 );\n        notify( value_c1 );\n        notify( value_c2 );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( notify_c1, test::request_with_reponse< server_with_multiple_char > )\n    {\n        l2cap_input( { 0x12, 0x0F, 0x00, 0x01, 0x00 } );\n        expected_result( { 0x13 } );\n\n        connection.queue_notification( 3 );\n        expected_output( value_c1, { 0x1B, 0x0E, 0x00, 0x04 } );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( notify_b1_on_two_connections, test::request_with_reponse< server_with_multiple_char > )\n    {\n        channel_data_t< bluetoe::details::link_state_no_security > con1, con2;\n\n        // enable notification on connection 1\n        l2cap_input( { 0x12, 0x0B, 0x00, 0x01, 0x00 }, con1 );\n        expected_result( { 0x13 } );\n\n        con1.queue_notification( 2 );\n\n        //  expect output just on connection 1\n        expected_output( value_b1, { 0x1B, 0x0A, 0x00, 0x03 }, con1 );\n        expected_output( value_b1, {}, con2 );\n\n    }\n\n\n    std::uint8_t fixed_value = 0xaa;\n\n    using fixed_server = bluetoe::server<\n        bluetoe::service<\n            bluetoe::service_uuid16< 0x8C8B >,\n            bluetoe::characteristic<\n                bluetoe::attribute_handles< 0x100, 0x110, 0x120 >,\n                bluetoe::characteristic_uuid16< 0x8C8B >,\n                bluetoe::bind_characteristic_value< std::uint8_t, &fixed_value >,\n                bluetoe::notify\n            >\n        >\n    >;\n\n    BOOST_FIXTURE_TEST_CASE( correct_handle_when_handles_are_fixed, test::request_with_reponse< fixed_server > )\n    {\n        // configure handle 0x120\n        l2cap_input( { 0x12, 0x20, 0x01, 0x01, 0x00 } );\n        expected_result( { 0x13 } );\n\n        notify< bluetoe::characteristic_uuid16< 0x8C8B > >();\n\n        BOOST_CHECK( notification.valid() );\n        BOOST_CHECK_EQUAL( notification.attribute_table_index(), 2u );\n        BOOST_CHECK_EQUAL( notification_type, bluetoe::details::notification_type::notification );\n\n        connection.queue_notification( 0 );\n        expected_output( notification, { 0x1B, 0x10, 0x01, 0xaa } );\n    }\n\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE( notifications_by_uuid )\n\n    static const std::uint16_t value1 = 0x1111;\n    static const std::uint16_t value2 = 0x2222;\n    static const std::uint16_t value3 = 0x3333;\n    static const std::uint16_t dummy  = 0x4444;\n\n    typedef bluetoe::server<\n        bluetoe::service<\n            bluetoe::service_uuid16< 0x8C8B >,\n            bluetoe::characteristic<\n                bluetoe::characteristic_uuid16< 0x1111 >,\n                bluetoe::bind_characteristic_value< decltype( value1 ), &value1 >,\n                bluetoe::notify\n            >,\n            bluetoe::characteristic<\n                bluetoe::characteristic_uuid16< 0xffff >,\n                bluetoe::bind_characteristic_value< decltype( dummy ), &dummy >\n            >,\n            bluetoe::characteristic<\n                bluetoe::characteristic_uuid16< 0x2222 >,\n                bluetoe::bind_characteristic_value< decltype( value2 ), &value2 >,\n                bluetoe::indicate,\n                bluetoe::notify\n            >\n        >,\n        bluetoe::service<\n            bluetoe::service_uuid16< 0x8C8C >,\n            bluetoe::characteristic<\n                bluetoe::characteristic_uuid16< 0xffff >,\n                bluetoe::bind_characteristic_value< decltype( dummy ), &dummy >\n            >,\n            bluetoe::characteristic<\n                bluetoe::characteristic_uuid16< 0x3333 >,\n                bluetoe::bind_characteristic_value< decltype( value3 ), &value3 >,\n                bluetoe::indicate\n            >\n        >\n    > server;\n\n    BOOST_FIXTURE_TEST_CASE( notify_first_16bit_uuid, test::request_with_reponse< server > )\n    {\n        notify< bluetoe::characteristic_uuid16< 0x1111 > >();\n\n        BOOST_REQUIRE( notification.valid() );\n        BOOST_CHECK_EQUAL( notification.attribute_table_index(), 2u );\n        BOOST_CHECK_EQUAL( notification.client_characteristic_configuration_index(), 0u );\n        BOOST_CHECK_EQUAL( notification_type, bluetoe::details::notification_type::notification );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( notify_second_16bit_uuid, test::request_with_reponse< server > )\n    {\n        notify< bluetoe::characteristic_uuid16< 0x2222 > >();\n\n        BOOST_REQUIRE( notification.valid() );\n        BOOST_CHECK_EQUAL( notification.attribute_table_index(), 7u );\n        BOOST_CHECK_EQUAL( notification.client_characteristic_configuration_index(), 1u );\n        BOOST_CHECK_EQUAL( notification_type, bluetoe::details::notification_type::notification );\n    }\n\n    // This test should not compile\n    /*\n    BOOST_FIXTURE_TEST_CASE( notify_third_16bit_uuid, request_with_reponse< server > )\n    {\n        notify< bluetoe::characteristic_uuid16< 0x3333 > >();\n    }\n    */\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE( access_client_characteristic_configuration )\n\n    std::uint8_t value1 = 0, value2;\n\n    typedef bluetoe::server<\n        bluetoe::service<\n            bluetoe::service_uuid16< 0x8C8B >,\n            bluetoe::characteristic<\n                bluetoe::characteristic_uuid16< 0x8C8B >,\n                bluetoe::bind_characteristic_value< std::uint8_t, &value1 >,\n                bluetoe::notify\n            >,\n            bluetoe::characteristic<\n                bluetoe::characteristic_uuid16< 0x8C8C >,\n                bluetoe::bind_characteristic_value< std::uint8_t, &value2 >,\n                bluetoe::notify\n            >\n        >\n    > simple_server;\n\n    BOOST_FIXTURE_TEST_CASE( read_default_values, test::request_with_reponse< simple_server > )\n    {\n        l2cap_input( { 0x0A, 0x04, 0x00 } );\n        expected_result( { 0x0B, 0x00, 0x00 } );\n\n        l2cap_input( { 0x0A, 0x07, 0x00 } );\n        expected_result( { 0x0B, 0x00, 0x00 } );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( read_blob_with_offset_1, test::request_with_reponse< simple_server > )\n    {\n        l2cap_input( { 0x0C, 0x04, 0x00, 0x01, 0x00 } );\n        expected_result( { 0x0D, 0x00 } );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( set_and_read, test::request_with_reponse< simple_server > )\n    {\n        l2cap_input( { 0x12, 0x04, 0x00, 0x01, 0x00 } );\n        expected_result( { 0x13 } );\n\n        l2cap_input( { 0x12, 0x07, 0x00, 0x00, 0x00 } );\n        expected_result( { 0x13 } );\n\n        // read by type\n        l2cap_input( { 0x08, 0x01, 0x00, 0xFF, 0xFF, 0x02, 0x29 } );\n        expected_result( {\n            0x09, 0x04,              // opcode and size\n            0x04, 0x00, 0x01, 0x00,  // handle and data\n            0x07, 0x00, 0x00, 0x00   // handle and data\n        } );\n    }\n\n    using server_decl_with_priorities = bluetoe::server<\n        bluetoe::service<\n            bluetoe::service_uuid16< 0x8C8B >,\n            bluetoe::characteristic<\n                bluetoe::characteristic_uuid16< 0x8C8B >,\n                bluetoe::bind_characteristic_value< std::uint8_t, &value1 >,\n                bluetoe::notify\n            >,\n            bluetoe::characteristic<\n                bluetoe::characteristic_uuid16< 0x8C8C >,\n                bluetoe::bind_characteristic_value< std::uint8_t, &value2 >,\n                bluetoe::indicate\n            >,\n\n            bluetoe::higher_outgoing_priority< bluetoe::characteristic_uuid16< 0x8C8C > >\n        >\n    >;\n\n    using server_with_priorities = test::request_with_reponse< server_decl_with_priorities >;\n\n    /*\n     * reproducer for #20 Writing to a CCCD leads to wrong CCCD beeing configured (when priorities are used)\n     */\n    BOOST_FIXTURE_TEST_CASE( configure_and_trigger, server_with_priorities )\n    {\n        // configure the first characteristics for notifications\n        l2cap_input( { 0x12, 0x04, 0x00, 0x01, 0x00 } );\n        expected_result( { 0x13 } );\n\n        notify< bluetoe::characteristic_uuid16< 0x8C8B > >();\n\n        BOOST_CHECK_EQUAL(\n            connection.client_configurations().flags( notification.client_characteristic_configuration_index() ),\n            0x01 );\n    }\n\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE( checking_proper_configuration )\n\n    struct handler\n    {\n        std::pair< std::uint8_t, bool > write_1( std::size_t, const std::uint8_t* )\n        {\n            return { bluetoe::error_codes::success, false };\n        }\n\n        std::uint8_t read_1( std::size_t, std::uint8_t*, std::size_t& )\n        {\n            return bluetoe::error_codes::success;\n        }\n\n    };\n\n    using uuid1 = bluetoe::characteristic_uuid16< 0x8C8C >;\n    using uuid2 = bluetoe::characteristic_uuid16< 0x8C8D >;\n\n    using server_decl_with_priorities = bluetoe::server<\n        bluetoe::service<\n            bluetoe::service_uuid16< 0x8C8B >,\n            bluetoe::mixin< handler >,\n            bluetoe::characteristic<\n                uuid1,\n                bluetoe::mixin_write_indication_control_point_handler<\n                    handler,\n                    &handler::write_1,\n                    uuid1\n                >,\n                bluetoe::mixin_read_handler<\n                    handler,\n                    &handler::read_1\n                >,\n                bluetoe::no_read_access,\n                bluetoe::indicate\n            >,\n            bluetoe::characteristic<\n                uuid2,\n                bluetoe::mixin_write_indication_control_point_handler<\n                    handler,\n                    &handler::write_1,\n                    uuid2\n                >,\n                bluetoe::mixin_read_handler<\n                    handler,\n                    &handler::read_1\n                >,\n                bluetoe::no_read_access,\n                bluetoe::indicate\n            >,\n\n            bluetoe::higher_outgoing_priority< uuid2 >\n        >\n    >;\n\n    using server_with_priorities = test::request_with_reponse< server_decl_with_priorities >;\n\n    BOOST_FIXTURE_TEST_CASE( check_unconfigured, server_with_priorities )\n    {\n        BOOST_CHECK( !configured_for_indications< uuid1 >( connection.client_configurations() ) );\n        BOOST_CHECK( !configured_for_indications< uuid2 >( connection.client_configurations() ) );\n        BOOST_CHECK( !configured_for_notifications< uuid1 >( connection.client_configurations() ) );\n        BOOST_CHECK( !configured_for_notifications< uuid2 >( connection.client_configurations() ) );\n        BOOST_CHECK( !configured_for_notifications_or_indications< uuid1 >( connection.client_configurations() ) );\n        BOOST_CHECK( !configured_for_notifications_or_indications< uuid2 >( connection.client_configurations() ) );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( configured_1_for_indications, server_with_priorities )\n    {\n        l2cap_input( { 0x12, 0x04, 0x00, 0x02, 0x00 } );\n        expected_result( { 0x13 } );\n\n        BOOST_CHECK(  configured_for_indications< uuid1 >( connection.client_configurations() ) );\n        BOOST_CHECK( !configured_for_indications< uuid2 >( connection.client_configurations() ) );\n        BOOST_CHECK( !configured_for_notifications< uuid1 >( connection.client_configurations() ) );\n        BOOST_CHECK( !configured_for_notifications< uuid2 >( connection.client_configurations() ) );\n        BOOST_CHECK(  configured_for_notifications_or_indications< uuid1 >( connection.client_configurations() ) );\n        BOOST_CHECK( !configured_for_notifications_or_indications< uuid2 >( connection.client_configurations() ) );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( configured_2_for_indications, server_with_priorities )\n    {\n        l2cap_input( { 0x12, 0x07, 0x00, 0x02, 0x00 } );\n        expected_result( { 0x13 } );\n\n        BOOST_CHECK( !configured_for_indications< uuid1 >( connection.client_configurations() ) );\n        BOOST_CHECK(  configured_for_indications< uuid2 >( connection.client_configurations() ) );\n        BOOST_CHECK( !configured_for_notifications< uuid1 >( connection.client_configurations() ) );\n        BOOST_CHECK( !configured_for_notifications< uuid2 >( connection.client_configurations() ) );\n        BOOST_CHECK( !configured_for_notifications_or_indications< uuid1 >( connection.client_configurations() ) );\n        BOOST_CHECK(  configured_for_notifications_or_indications< uuid2 >( connection.client_configurations() ) );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( configured_both_for_indications, server_with_priorities )\n    {\n        l2cap_input( { 0x12, 0x04, 0x00, 0x02, 0x00 } );\n        expected_result( { 0x13 } );\n\n        l2cap_input( { 0x12, 0x07, 0x00, 0x02, 0x00 } );\n        expected_result( { 0x13 } );\n\n        BOOST_CHECK( configured_for_indications< uuid1 >( connection.client_configurations() ) );\n        BOOST_CHECK( configured_for_indications< uuid2 >( connection.client_configurations() ) );\n        BOOST_CHECK( !configured_for_notifications< uuid1 >( connection.client_configurations() ) );\n        BOOST_CHECK( !configured_for_notifications< uuid2 >( connection.client_configurations() ) );\n        BOOST_CHECK( configured_for_notifications_or_indications< uuid1 >( connection.client_configurations() ) );\n        BOOST_CHECK( configured_for_notifications_or_indications< uuid2 >( connection.client_configurations() ) );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( correct_uuid_beeing_tested_in_control_point_handler, server_with_priorities )\n    {\n        // configure the second characteristics for indication\n        l2cap_input( { 0x12, 0x07, 0x00, 0x02, 0x00 } );\n        expected_result( { 0x13 } );\n\n        // write to second control point\n        l2cap_input( { 0x12, 0x06, 0x00, 0x42 } );\n        expected_result( { 0x13 } );\n\n        // write to first control point\n        l2cap_input( { 0x12, 0x03, 0x00, 0x42 } );\n        expected_result( { 0x01, 0x12, 0x03, 0x00, 0xfd } );\n    }\n\nBOOST_AUTO_TEST_SUITE_END()\n\n/*\n * While working on DTS, there showed up a bug...\n */\nBOOST_AUTO_TEST_SUITE( priorites_charactieristics )\n\n    struct dts_service\n    {\n        dts_service()\n            : read_features_called( 0 )\n            , read_parameters_called( 0 )\n            , read_device_time_called( 0 )\n            , write_control_point_called( 0 )\n            , read_control_point_called( 0 )\n            , read_log_data_called( 0 )\n            , write_log_access_control_point_called( 0 )\n            , read_log_access_control_point_called( 0 )\n        {\n        }\n\n        std::uint8_t read_features( std::size_t, std::uint8_t*, std::size_t& )\n        {\n            ++read_features_called;\n\n            return bluetoe::error_codes::success;\n        }\n\n        std::uint8_t read_parameters( std::size_t, std::uint8_t*, std::size_t& )\n        {\n            ++read_parameters_called;\n            return bluetoe::error_codes::success;\n        }\n\n        std::uint8_t read_device_time( std::size_t, std::uint8_t*, std::size_t& )\n        {\n            ++read_device_time_called;\n            return bluetoe::error_codes::success;\n        }\n\n        std::pair< std::uint8_t, bool > write_control_point( std::size_t, const std::uint8_t* )\n        {\n            ++write_control_point_called;\n            return { bluetoe::error_codes::success, true };\n        }\n\n        std::uint8_t read_control_point( std::size_t, std::uint8_t*, std::size_t& )\n        {\n            ++read_control_point_called;\n            return bluetoe::error_codes::success;\n        }\n\n        std::uint8_t read_log_data( std::size_t, std::uint8_t*, std::size_t& )\n        {\n            ++read_log_data_called;\n            return bluetoe::error_codes::success;\n        }\n\n        std::pair< std::uint8_t, bool > write_log_access_control_point( std::size_t, const std::uint8_t* )\n        {\n            ++write_log_access_control_point_called;\n            return { bluetoe::error_codes::success, true };\n        }\n\n        std::uint8_t read_log_access_control_point( std::size_t, std::uint8_t*, std::size_t& )\n        {\n            ++read_log_access_control_point_called;\n            return bluetoe::error_codes::success;\n        }\n\n        template < typename Server, typename ConData >\n        void read_output_handler( Server& srv, ConData& connection )\n        {\n            std::uint8_t    buffer[ 100 ];\n            std::size_t     size = sizeof( buffer );\n\n            srv.l2cap_output( buffer, size, connection );\n        }\n\n        unsigned read_features_called;\n        unsigned read_parameters_called;\n        unsigned read_device_time_called;\n        unsigned write_control_point_called;\n        unsigned read_control_point_called;\n        unsigned read_log_data_called;\n        unsigned write_log_access_control_point_called;\n        unsigned read_log_access_control_point_called;\n    };\n\n    using dts_service_uuid                  = bluetoe::service_uuid16< 0xff00 >;\n\n    using device_time_feature_uuid          = bluetoe::characteristic_uuid16< 0x1234 >;\n    using device_time_parameters_uuid       = bluetoe::characteristic_uuid16< 0x1235 >;\n    using device_time_uuid                  = bluetoe::characteristic_uuid16< 0x1236 >;\n    using device_time_control_point_uuid    = bluetoe::characteristic_uuid16< 0x1237 >;\n    using time_change_log_data_uuid         = bluetoe::characteristic_uuid16< 0x1238 >;\n    using record_access_control_point_uuid  = bluetoe::characteristic_uuid16< 0x1239 >;\n\n    /*\n     * Definition of the GATT structure of the IDS server\n     */\n    template < class ServiceImpl >\n    using dts_server_t = bluetoe::server<\n        /*\n         * One primary service\n         */\n        bluetoe::service<\n            dts_service_uuid,\n\n            /*\n             * Mandatory Characteristics\n             */\n            bluetoe::characteristic<\n                device_time_feature_uuid,\n                bluetoe::mixin_read_handler< dts_service, &dts_service::read_features >\n            >,\n            bluetoe::characteristic<\n                device_time_parameters_uuid,\n                bluetoe::mixin_read_handler< dts_service, &dts_service::read_parameters >\n            >,\n            bluetoe::characteristic<\n                device_time_uuid,\n                bluetoe::mixin_read_handler< dts_service, &dts_service::read_device_time >,\n                bluetoe::indicate\n            >,\n\n            /*\n             * Control Point\n             */\n            bluetoe::characteristic<\n                device_time_control_point_uuid,\n                bluetoe::mixin_write_indication_control_point_handler<\n                    dts_service,\n                    &dts_service::write_control_point,\n                    device_time_control_point_uuid\n                >,\n                bluetoe::mixin_read_handler<\n                    dts_service,\n                    &dts_service::read_control_point\n                >,\n                bluetoe::no_read_access,\n                bluetoe::indicate\n            >,\n\n            /*\n             * Log\n             */\n            bluetoe::characteristic<\n                time_change_log_data_uuid,\n                bluetoe::mixin_read_handler< dts_service, &dts_service::read_log_data >,\n                bluetoe::notify,\n                bluetoe::no_read_access\n            >,\n            bluetoe::characteristic<\n                record_access_control_point_uuid,\n                bluetoe::mixin_write_indication_control_point_handler<\n                    dts_service,\n                    &dts_service::write_log_access_control_point,\n                    record_access_control_point_uuid\n                >,\n                bluetoe::mixin_read_handler<\n                    dts_service,\n                    &dts_service::read_log_access_control_point\n                >,\n                bluetoe::no_read_access,\n                bluetoe::indicate\n            >,\n\n            /*\n             * Mixin a dts_service implementation\n             */\n            bluetoe::mixin< ServiceImpl >,\n\n            /*\n             * Make sure, that log data is transmitted with higher priority\n             */\n            bluetoe::higher_outgoing_priority< time_change_log_data_uuid >\n        >\n    >;\n\n    using test_server = test::request_with_reponse< dts_server_t< dts_service > >;\n\n    static bool lcap_notification_callback( const ::bluetoe::details::notification_data& item, void* that, bluetoe::details::notification_type type )\n    {\n        auto& notification_queue = *static_cast< test_server* >( that );\n        switch ( type )\n        {\n            case bluetoe::details::notification_type::notification:\n                return notification_queue.connection.queue_notification( item.client_characteristic_configuration_index() );\n                break;\n            case bluetoe::details::notification_type::indication:\n                return notification_queue.connection.queue_indication( item.client_characteristic_configuration_index() );\n                break;\n            case bluetoe::details::notification_type::confirmation:\n                notification_queue.connection.indication_confirmed();\n                return true;\n                break;\n        }\n\n        return true;\n    }\n\n    BOOST_FIXTURE_TEST_CASE( inidicating_control_point_leads_to_reading_control_point, test_server )\n    {\n        notification_callback( lcap_notification_callback, this );\n\n        // connect and subscribe to all characteristics\n        for ( unsigned config = 0; config != connection_data::number_of_characteristics_with_configuration; ++config )\n            connection.client_configurations().flags( config, 0x03 );\n\n        // mark the log data characteristic to have data\n        notify< time_change_log_data_uuid >();\n\n        // simulate that there is one free output buffer on the link layer.\n        read_output_handler( *this, connection );\n\n        // the ATT layer should choose the characteristic with the highest output priorit\n        BOOST_CHECK_EQUAL( read_log_data_called, 1u );\n        BOOST_CHECK_EQUAL( read_device_time_called, 0u );\n        BOOST_CHECK_EQUAL( read_control_point_called, 0u );\n        BOOST_CHECK_EQUAL( read_log_access_control_point_called, 0u );\n\n        // same with the control point\n        indicate< device_time_control_point_uuid >();\n\n        read_output_handler( *this, connection );\n        BOOST_CHECK_EQUAL( read_log_data_called, 1u );\n        BOOST_CHECK_EQUAL( read_device_time_called, 0u );\n        BOOST_CHECK_EQUAL( read_control_point_called, 1u );\n        BOOST_CHECK_EQUAL( read_log_access_control_point_called, 0u );\n    }\n\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE( double_used_uuid )\n\n    std::uint8_t value1 = 1;\n    std::uint8_t value2 = 2;\n\n    using first_char =\n        bluetoe::characteristic<\n            bluetoe::characteristic_uuid16< 0x8C8B >,\n            bluetoe::bind_characteristic_value< std::uint8_t, &value1 >,\n            bluetoe::notify\n        >;\n\n    using second_char =\n        bluetoe::characteristic<\n            bluetoe::characteristic_uuid16< 0x8C8B >,\n            bluetoe::bind_characteristic_value< std::uint8_t, &value2 >\n        >;\n\n    using service =\n        bluetoe::service<\n            bluetoe::service_uuid16< 0x8C8B >,\n            first_char,\n            second_char\n        >;\n\n    using simple_server = bluetoe::server<\n        service,\n        bluetoe::no_gap_service_for_gatt_servers >;\n\n    BOOST_AUTO_TEST_CASE( attribute_numbers )\n    {\n        BOOST_CHECK_EQUAL( std::size_t{ first_char::number_of_attributes }, 3u );\n        BOOST_CHECK_EQUAL( std::size_t{ second_char::number_of_attributes }, 2u );\n        BOOST_CHECK_EQUAL( std::size_t{ service::number_of_attributes }, 6u );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( expected_attributes_first_char, test::request_with_reponse< simple_server > )\n    {\n        /*\n         * first characteristic\n         */\n        l2cap_input( {\n            0x0A,                           // Read Request\n            0x02, 0x00                      // Handle\n        } );\n\n        expected_result( {\n            0x0B,                           // Read Response\n            0x1A,                           // Properties (read, write, and notify)\n            0x03, 0x00,                     // Value Handle\n            0x8B, 0x8C                      // UUID\n        } );\n\n        l2cap_input( {\n            0x0A,                           // Read Request\n            0x03, 0x00                      // Value Handle\n        } );\n\n        expected_result( {\n            0x0B,                           // Read Response\n            0x01                            // Value\n        } );\n\n        l2cap_input( {\n            0x0A,                           // Read Request\n            0x04, 0x00                      // CCCD Handle\n        } );\n\n        expected_result( {\n            0x0B,                           // Read Response\n            0x00, 0x00                      // Value\n        } );\n\n        /*\n         * second characteristic\n         */\n        l2cap_input( {\n            0x0A,                           // Read Request\n            0x05, 0x00                      // Handle\n        } );\n\n        expected_result( {\n            0x0B,                           // Read Response\n            0x0A,                           // Properties (read, write)\n            0x06, 0x00,                     // Value Handle\n            0x8B, 0x8C                      // UUID\n        } );\n\n        l2cap_input( {\n            0x0A,                           // Read Request\n            0x06, 0x00                      // Value Handle\n        } );\n\n        expected_result( {\n            0x0B,                           // Read Response\n            0x02                            // Value\n        } );\n\n        l2cap_input( {\n            0x0A,                           // Read Request\n            0x07, 0x00                      // invalid hande\n        } );\n\n        expected_result( {\n            0x01,                           // Error Response\n            0x0A,                           // Request Opcode\n            0x07, 0x00,                     // Handle\n            0x01                            // Invalid Handle\n        } );\n    }\n\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE( access_error )\n\n    std::uint8_t error( std::size_t, std::uint8_t*, std::size_t& )\n    {\n        // something != bluetoe::error_codes::success;\n        return bluetoe::error_codes::invalid_pdu;\n    }\n\n    using server = bluetoe::server<\n        bluetoe::service<\n            bluetoe::service_uuid16< 0x1234 >,\n            bluetoe::characteristic<\n                bluetoe::free_read_handler< &error >,\n                bluetoe::characteristic_uuid16< 0x0001 >,\n                bluetoe::notify\n            >\n        >\n    >;\n\n    BOOST_FIXTURE_TEST_CASE( read_error, test::request_with_reponse< server > )\n    {\n        l2cap_input( { 0x12, 0x04, 0x00, 0x01, 0x00 } );\n\n        std::uint8_t output_buffer[ 50 ];\n        std::size_t  output_size = sizeof( output_buffer );\n\n        l2cap_output( output_buffer, output_size , connection );\n\n        BOOST_CHECK_EQUAL( output_size, 0u );\n    }\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "tests/att/outgoing_priority_tests.cpp",
    "content": "#define BOOST_TEST_MODULE\n#include <boost/test/included/unit_test.hpp>\n\n#include <bluetoe/server.hpp>\n#include <bluetoe/service.hpp>\n#include <bluetoe/characteristic.hpp>\n#include <bluetoe/outgoing_priority.hpp>\n\n/*\n * The purpose of this tests is to make sure, that lower_outgoing_priority and higher_outgoing_priority\n * are correctly interpreted. That the notification_queue acts correctly under all curcumstances will\n * be tested within the queue tests.\n */\nconst std::uint8_t value = 0xAa;\n\nusing A = bluetoe::service_uuid16< 0x1234 >;\n\nusing A_a = bluetoe::characteristic_uuid16< 0xFF00 >;\nusing A_b = bluetoe::characteristic_uuid16< 0xFF01 >;\nusing A_c = bluetoe::characteristic_uuid16< 0xFF02 >;\n\nusing B = bluetoe::service_uuid16< 0x1235 >;\n\nusing B_a = bluetoe::characteristic_uuid16< 0xFF10 >;\nusing B_b = bluetoe::characteristic_uuid16< 0xFF11 >;\nusing B_c = bluetoe::characteristic_uuid16< 0xFF12 >;\n\ntemplate < typename UUID, typename ...Options >\nusing characteristic =\n    bluetoe::characteristic<\n        bluetoe::bind_characteristic_value< const std::uint8_t, &value >,\n        UUID,\n        bluetoe::notify,\n        Options...\n    >;\n\nusing charA_a = characteristic< A_a >;\nusing charA_b = characteristic< A_b >;\nusing charA_c = characteristic< A_c >;\n\nusing charB_a = characteristic< B_a >;\nusing charB_b = characteristic< B_b >;\nusing charB_c = characteristic< B_c >;\n\nusing service_A = bluetoe::service<\n        A,\n        charA_a,\n        charA_b\n    >;\n\nusing service_B = bluetoe::service<\n        B,\n        charB_a,\n        charB_b\n    >;\n\nBOOST_AUTO_TEST_CASE( equal_default_priority )\n{\n    using server   = bluetoe::server< service_A, service_B >;\n    using services = server::services;\n    using prio     = typename server::notification_priority;\n\n    BOOST_CHECK_EQUAL( int( prio::characteristic_priority< services, service_A, charA_a >::value ), 0 );\n    BOOST_CHECK_EQUAL( int( prio::characteristic_priority< services, service_A, charA_b >::value ), 0 );\n    BOOST_CHECK_EQUAL( int( prio::characteristic_priority< services, service_B, charB_a >::value ), 0 );\n    BOOST_CHECK_EQUAL( int( prio::characteristic_priority< services, service_B, charB_b >::value ), 0 );\n}\n\nBOOST_AUTO_TEST_CASE( raised_priority_in_one_char )\n{\n    using service_A = bluetoe::service<\n            A,\n            charA_a,\n            charA_b,\n            charA_c,\n            bluetoe::higher_outgoing_priority< A_b >\n        >;\n\n    using server   = bluetoe::server< service_A, service_B >;\n    using services = server::services;\n    using prio     = typename server::notification_priority;\n\n    BOOST_CHECK_EQUAL( int( prio::characteristic_priority< services, service_A, charA_b >::value ), 0 );\n    BOOST_CHECK_EQUAL( int( prio::characteristic_priority< services, service_A, charA_a >::value ), 1 );\n    BOOST_CHECK_EQUAL( int( prio::characteristic_priority< services, service_A, charA_c >::value ), 1 );\n    BOOST_CHECK_EQUAL( int( prio::characteristic_priority< services, service_B, charB_a >::value ), 1 );\n    BOOST_CHECK_EQUAL( int( prio::characteristic_priority< services, service_B, charB_c >::value ), 1 );\n}\n\nBOOST_AUTO_TEST_CASE( raised_priotity_on_all_services )\n{\n    using service_A = bluetoe::service<\n            A,\n            charA_a,\n            charA_b,\n            bluetoe::higher_outgoing_priority< A_a >\n        >;\n\n    using service_B = bluetoe::service<\n            B,\n            charB_a,\n            charB_b,\n            bluetoe::higher_outgoing_priority< B_a, B_b >\n        >;\n\n    using server   = bluetoe::server< service_A, service_B >;\n    using services = server::services;\n    using prio     = typename server::notification_priority;\n\n    BOOST_CHECK_EQUAL( int( prio::characteristic_priority< services, service_B, charB_a >::value ), 0 );\n    BOOST_CHECK_EQUAL( int( prio::characteristic_priority< services, service_A, charA_a >::value ), 1 );\n    BOOST_CHECK_EQUAL( int( prio::characteristic_priority< services, service_B, charB_b >::value ), 1 );\n    BOOST_CHECK_EQUAL( int( prio::characteristic_priority< services, service_A, charA_b >::value ), 2 );\n}\n\nBOOST_AUTO_TEST_CASE( raised_priority_in_two_chars )\n{\n    using service_A = bluetoe::service<\n            A,\n            charA_a,\n            charA_b,\n            charA_c,\n            bluetoe::higher_outgoing_priority< A_b, A_a >\n        >;\n\n    using server   = bluetoe::server< service_A >;\n    using services = server::services;\n    using prio    = typename server::notification_priority;\n\n    BOOST_CHECK_EQUAL( int( prio::characteristic_priority< services, service_A, charA_b >::value ), 0 );\n    BOOST_CHECK_EQUAL( int( prio::characteristic_priority< services, service_A, charA_a >::value ), 1 );\n    BOOST_CHECK_EQUAL( int( prio::characteristic_priority< services, service_A, charA_c >::value ), 2 );\n}\n\nBOOST_AUTO_TEST_CASE( raised_priority_of_one_service )\n{\n    using server   = bluetoe::server< service_A, service_B, bluetoe::higher_outgoing_priority< A > >;\n    using services = server::services;\n    using prio     = typename server::notification_priority;\n\n    BOOST_CHECK_EQUAL( int( prio::characteristic_priority< services, service_A, charA_a >::value ), 0 );\n    BOOST_CHECK_EQUAL( int( prio::characteristic_priority< services, service_A, charA_b >::value ), 0 );\n    BOOST_CHECK_EQUAL( int( prio::characteristic_priority< services, service_B, charB_a >::value ), 1 );\n    BOOST_CHECK_EQUAL( int( prio::characteristic_priority< services, service_B, charB_b >::value ), 1 );\n}\n\nBOOST_AUTO_TEST_CASE( default_prio_of_raise_service_is_higher_than_default_prio_in_other_service )\n{\n    using service_A = bluetoe::service<\n            A,\n            charA_a,\n            charA_b,\n            bluetoe::higher_outgoing_priority< A_a >\n        >;\n\n    using server   = bluetoe::server< service_A, service_B, bluetoe::higher_outgoing_priority< A > >;\n    using services = server::services;\n    using prio     = typename server::notification_priority;\n\n    BOOST_CHECK_EQUAL( int( prio::characteristic_priority< services, service_A, charA_a >::value ), 0 );\n    BOOST_CHECK_EQUAL( int( prio::characteristic_priority< services, service_A, charA_b >::value ), 1 );\n    BOOST_CHECK_EQUAL( int( prio::characteristic_priority< services, service_B, charB_a >::value ), 2 );\n    BOOST_CHECK_EQUAL( int( prio::characteristic_priority< services, service_B, charB_b >::value ), 2 );\n}\n\nBOOST_AUTO_TEST_CASE( no_additional_prio_if_all_chars_of_a_service_have_none_default_prio )\n{\n    using service_A = bluetoe::service<\n            A,\n            charA_a,\n            charA_b,\n            bluetoe::higher_outgoing_priority< A_a, A_b >\n        >;\n\n    using server   = bluetoe::server< service_A, service_B, bluetoe::higher_outgoing_priority< A > >;\n    using services = server::services;\n    using prio     = typename server::notification_priority;\n\n    BOOST_CHECK_EQUAL( int( prio::characteristic_priority< services, service_A, charA_a >::value ), 0 );\n    BOOST_CHECK_EQUAL( int( prio::characteristic_priority< services, service_A, charA_b >::value ), 1 );\n    BOOST_CHECK_EQUAL( int( prio::characteristic_priority< services, service_B, charB_a >::value ), 2 );\n    BOOST_CHECK_EQUAL( int( prio::characteristic_priority< services, service_B, charB_b >::value ), 2 );\n}\n\n// second time, make sure that only characteristics with CCCD count\nBOOST_AUTO_TEST_CASE( no_additional_prio_if_all_chars_of_a_service_have_none_default_prio_II )\n{\n    using charA_b =\n        bluetoe::characteristic<\n            bluetoe::bind_characteristic_value< const std::uint8_t, &value >,\n            A_b\n        >;\n\n    using service_A = bluetoe::service<\n            A,\n            charA_a,\n            charA_b,\n            bluetoe::higher_outgoing_priority< A_a >\n        >;\n\n    using server   = bluetoe::server< service_A, service_B, bluetoe::higher_outgoing_priority< A > >;\n    using services = server::services;\n    using prio     = typename server::notification_priority;\n\n    BOOST_CHECK_EQUAL( int( prio::characteristic_priority< services, service_A, charA_a >::value ), 0 );\n    BOOST_CHECK_EQUAL( int( prio::characteristic_priority< services, service_B, charB_a >::value ), 1 );\n    BOOST_CHECK_EQUAL( int( prio::characteristic_priority< services, service_B, charB_b >::value ), 1 );\n}\n\nBOOST_AUTO_TEST_CASE( raised_prio_in_one_char_and_raised_prio_in_other_service )\n{\n    using service_B = bluetoe::service<\n            B,\n            charB_a,\n            charB_b,\n            bluetoe::higher_outgoing_priority< B_a  >\n        >;\n\n    using server   = bluetoe::server< service_A, service_B, bluetoe::higher_outgoing_priority< A > >;\n    using services = server::services;\n    using prio     = typename server::notification_priority;\n\n    BOOST_CHECK_EQUAL( int( prio::characteristic_priority< services, service_A, charA_a >::value ), 0 );\n    BOOST_CHECK_EQUAL( int( prio::characteristic_priority< services, service_A, charA_b >::value ), 0 );\n    BOOST_CHECK_EQUAL( int( prio::characteristic_priority< services, service_B, charB_a >::value ), 1 );\n    BOOST_CHECK_EQUAL( int( prio::characteristic_priority< services, service_B, charB_b >::value ), 2 );\n}\n\nBOOST_AUTO_TEST_CASE( two_services_with_similar_characteristic_priorities_but_different_service_priority )\n{\n    using service_A = bluetoe::service<\n            A,\n            charA_a,\n            charA_b,\n            charA_c,\n            bluetoe::higher_outgoing_priority< A_a, A_b >\n        >;\n\n    using service_B = bluetoe::service<\n            B,\n            charB_a,\n            charB_b,\n            charB_c,\n            bluetoe::higher_outgoing_priority< B_a >\n        >;\n\n    using server   = bluetoe::server< service_A, service_B, bluetoe::higher_outgoing_priority< A > >;\n    using services = server::services;\n    using prio     = typename server::notification_priority;\n\n    BOOST_CHECK_EQUAL( int( prio::characteristic_priority< services, service_A, charA_a >::value ), 0 );\n    BOOST_CHECK_EQUAL( int( prio::characteristic_priority< services, service_A, charA_b >::value ), 1 );\n    BOOST_CHECK_EQUAL( int( prio::characteristic_priority< services, service_A, charA_c >::value ), 2 );\n    BOOST_CHECK_EQUAL( int( prio::characteristic_priority< services, service_B, charB_a >::value ), 3 );\n    BOOST_CHECK_EQUAL( int( prio::characteristic_priority< services, service_B, charB_b >::value ), 4 );\n    BOOST_CHECK_EQUAL( int( prio::characteristic_priority< services, service_B, charB_c >::value ), 4 );\n}\n\ntemplate < std::size_t I >\nusing int_c = std::integral_constant< int, I >;\n\nBOOST_AUTO_TEST_CASE( numbers_for_single_priority )\n{\n    using server   = bluetoe::server< service_A, service_B >;\n    using services = server::services;\n    using prio     = typename server::notification_priority;\n\n    BOOST_CHECK((\n        std::is_same<\n            typename prio::numbers< services >::type,\n            std::tuple< int_c< 4 > >\n        >::value\n    ));\n}\n\nBOOST_AUTO_TEST_CASE( priority_numbers_for_an_example_with_two_services )\n{\n    using service_A = bluetoe::service<\n            A,\n            charA_a,\n            charA_b,\n            bluetoe::higher_outgoing_priority< A_a >\n        >;\n\n    using server   = bluetoe::server< service_A, service_B, bluetoe::higher_outgoing_priority< A > >;\n    using services = server::services;\n    using prio     = typename server::notification_priority;\n\n    BOOST_CHECK((\n        std::is_same<\n            typename prio::numbers< services >::type,\n            std::tuple< int_c< 1 >, int_c< 1 >, int_c< 2 > >\n        >::value\n    ));\n}\n\nBOOST_AUTO_TEST_CASE( priority_numbers_for_two_services_with_similar_characteristic_priorities_but_different_service_priority )\n{\n    using service_A = bluetoe::service<\n            A,\n            charA_a,\n            charA_b,\n            charA_c,\n            bluetoe::higher_outgoing_priority< A_a, A_b >\n        >;\n\n    using service_B = bluetoe::service<\n            B,\n            charB_a,\n            charB_b,\n            charB_c,\n            bluetoe::higher_outgoing_priority< B_a >\n        >;\n\n    using server   = bluetoe::server< service_A, service_B, bluetoe::higher_outgoing_priority< A > >;\n    using services = server::services;\n    using prio     = typename server::notification_priority;\n\n    BOOST_CHECK((\n        std::is_same<\n            typename prio::numbers< services >::type,\n            std::tuple< int_c< 1 >, int_c< 1 >, int_c< 1 >, int_c< 1 >, int_c< 2 > >\n        >::value\n    ));\n}\n\n\nBOOST_AUTO_TEST_CASE( add_prio_tests )\n{\n    using namespace bluetoe::details;\n\n    BOOST_CHECK((\n        std::is_same<\n            typename add_prio< std::tuple<>, 0 >::type,\n            std::tuple< int_c< 1 > >\n        >::value\n    ));\n\n    BOOST_CHECK((\n        std::is_same<\n            typename add_prio< std::tuple< int_c< 3 > >, 0 >::type,\n            std::tuple< int_c< 4 > >\n        >::value\n    ));\n\n    BOOST_CHECK((\n        std::is_same<\n            typename add_prio< std::tuple<>, 2 >::type,\n            std::tuple< int_c< 0 >, int_c< 0 >, int_c< 1 > >\n        >::value\n    ));\n\n    BOOST_CHECK((\n        std::is_same<\n            typename add_prio< std::tuple< int_c< 3 >, int_c< 2 > >, 0 >::type,\n            std::tuple< int_c< 4 >, int_c< 2 > >\n        >::value\n    ));\n\n    BOOST_CHECK((\n        std::is_same<\n            typename add_prio< std::tuple< int_c< 3 >, int_c< 2 >, int_c< 1 > >, 1 >::type,\n            std::tuple< int_c< 3 >, int_c< 3 >, int_c< 1 > >\n        >::value\n    ));\n\n    BOOST_CHECK((\n        std::is_same<\n            typename add_prio< std::tuple< int_c< 3 >, int_c< 2 >, int_c< 1 > >, 4 >::type,\n            std::tuple< int_c< 3 >, int_c< 2 >, int_c< 1 >, int_c< 0 >, int_c< 1 > >\n        >::value\n    ));\n}\n\n"
  },
  {
    "path": "tests/att/prepare_write_tests.cpp",
    "content": "#define BOOST_TEST_MODULE\n#include <boost/test/included/unit_test.hpp>\n\n#include \"test_servers.hpp\"\n\nBOOST_AUTO_TEST_SUITE( prepare_write_errors )\n\nBOOST_FIXTURE_TEST_CASE( no_write_buffer, test::request_with_reponse< test::three_apes_service > )\n{\n    BOOST_CHECK( check_error_response( { 0x16, 0x03, 0x00, 0x00, 0x00, 0xab  }, 0x16, 0x0000, 0x06 ) );\n}\n\nstd::uint8_t very_large_value[ 64 ] = {\n    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,\n    0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,\n    0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,\n    0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F\n};\n\ntypedef bluetoe::server<\n    bluetoe::shared_write_queue< ( ( sizeof( very_large_value ) + 17 ) / 18 * 7 ) + sizeof( very_large_value ) >,\n    bluetoe::service<\n        bluetoe::service_uuid< 0x8C8B4094, 0x0DE2, 0x499F, 0xA28A, 0x4EED5BC73CA9 >,\n        bluetoe::characteristic<\n            bluetoe::characteristic_uuid< 0x8C8B4094, 0x0DE2, 0x499F, 0xA28A, 0x4EED5BC73CAA >,\n            bluetoe::bind_characteristic_value< decltype( very_large_value ), &very_large_value >\n        >\n    >\n> very_large_value_server;\n\ntypedef test::request_with_reponse< very_large_value_server > large_fixture;\n\nBOOST_FIXTURE_TEST_CASE( pdu_to_small, large_fixture )\n{\n    BOOST_CHECK( check_error_response( { 0x16, 0x03, 0x00 }, 0x16, 0x0000, 0x04 ) );\n}\n\nBOOST_FIXTURE_TEST_CASE( no_such_handle, large_fixture )\n{\n    BOOST_CHECK( check_error_response( { 0x16, 0x17, 0xAA, 0x00, 0x00, 0x12, 0x23 }, 0x16, 0xAA17, 0x01 ) );\n}\n\nBOOST_FIXTURE_TEST_CASE( invalid_handle, large_fixture )\n{\n    BOOST_CHECK( check_error_response( { 0x16, 0x00, 0x00, 0x00, 0x00 }, 0x16, 0x0000, 0x01 ) );\n}\n\nBOOST_FIXTURE_TEST_CASE( write_protected, large_fixture )\n{\n    BOOST_CHECK( check_error_response( { 0x16, 0x01, 0x00, 0x00, 0x00 }, 0x16, 0x0001, 0x03 ) );\n}\n\ntypedef bluetoe::server<\n    bluetoe::shared_write_queue< 12 >,\n    bluetoe::service<\n        bluetoe::service_uuid< 0x8C8B4094, 0x0DE2, 0x499F, 0xA28A, 0x4EED5BC73CA9 >,\n        bluetoe::characteristic<\n            bluetoe::characteristic_uuid< 0x8C8B4094, 0x0DE2, 0x499F, 0xA28A, 0x4EED5BC73CAA >,\n            bluetoe::bind_characteristic_value< decltype( very_large_value ), &very_large_value >\n        >\n    >\n> large_value_server_with_small_queue;\n\nBOOST_FIXTURE_TEST_CASE( write_queue_full, test::request_with_reponse< large_value_server_with_small_queue > )\n{\n    BOOST_CHECK( check_error_response(\n        { 0x16, 0x03, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 },\n        0x16, 0x0003, 0x09 ) );\n}\n\nBOOST_FIXTURE_TEST_CASE( write_queue_used_by_other_client, large_fixture )\n{\n    channel_data_t< bluetoe::details::link_state_no_security > con1;\n    channel_data_t< bluetoe::details::link_state_no_security > con2;\n\n    l2cap_input( { 0x16, 0x03, 0x00, 0x00, 0x00, 0x00, 0x01 }, con1 );\n    expected_result( { 0x17, 0x03, 0x00, 0x00, 0x00, 0x00, 0x01 } );\n\n    l2cap_input( { 0x16, 0x03, 0x00, 0x00, 0x00, 0x00, 0x01 }, con2 );\n    expected_result( { 0x01, 0x16, 0x03, 0x00, 0x09 } );\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE( prepare_writes )\n\nstd::uint16_t ape1 = 1, ape2 = 2, ape3 = 3;\n\ntypedef bluetoe::server<\n    bluetoe::shared_write_queue< 30 >,\n    bluetoe::service<\n        bluetoe::service_uuid< 0x8C8B4094, 0x0DE2, 0x499F, 0xA28A, 0x4EED5BC73CA9 >,\n        bluetoe::characteristic<\n            bluetoe::characteristic_uuid< 0x8C8B4094, 0x0DE2, 0x499F, 0xA28A, 0x4EED5BC73CAA >,\n            bluetoe::bind_characteristic_value< std::uint16_t, &ape1 >\n        >,\n        bluetoe::characteristic<\n            bluetoe::characteristic_uuid< 0x8C8B4094, 0x0DE2, 0x499F, 0xA28A, 0x4EED5BC73CAB >,\n            bluetoe::bind_characteristic_value< std::uint16_t, &ape2 >\n        >,\n        bluetoe::characteristic<\n            bluetoe::characteristic_uuid< 0x8C8B4094, 0x0DE2, 0x499F, 0xA28A, 0x4EED5BC73CAC >,\n            bluetoe::bind_characteristic_value< std::uint16_t, &ape3 >\n        >\n    >\n> three_apes_server;\n\nBOOST_FIXTURE_TEST_CASE( prepare_3_writes, test::request_with_reponse< three_apes_server > )\n{\n    l2cap_input( { 0x16, 0x03, 0x00, 0x00, 0x00, 0x00, 0x01 } );\n    expected_result( { 0x17, 0x03, 0x00, 0x00, 0x00, 0x00, 0x01 } );\n\n    l2cap_input( { 0x16, 0x05, 0x00, 0x00, 0x00, 0x00, 0x02 } );\n    expected_result( { 0x17, 0x05, 0x00, 0x00, 0x00, 0x00, 0x02 } );\n\n    l2cap_input( { 0x16, 0x07, 0x00, 0x00, 0x00, 0x00, 0x03 } );\n    expected_result( { 0x17, 0x07, 0x00, 0x00, 0x00, 0x00, 0x03 } );\n}\n\nBOOST_FIXTURE_TEST_CASE( queue_can_be_used_after_beeing_released, test::request_with_reponse< three_apes_server > )\n{\n    channel_data_t< bluetoe::details::link_state_no_security > con1;\n    channel_data_t< bluetoe::details::link_state_no_security > con2;\n\n    l2cap_input( { 0x16, 0x03, 0x00, 0x00, 0x00, 0x00, 0x01 }, con1 );\n\n    l2cap_input( { 0x16, 0x03, 0x00, 0x00, 0x00, 0x00, 0x01 }, con2 );\n    expected_result( { 0x01, 0x16, 0x03, 0x00, 0x09 } );\n\n    this->client_disconnected( con1 );\n\n    l2cap_input( { 0x16, 0x03, 0x00, 0x00, 0x00, 0x00, 0x01 }, con2 );\n    expected_result( { 0x17, 0x03, 0x00, 0x00, 0x00, 0x00, 0x01 } );\n}\n\nBOOST_FIXTURE_TEST_CASE( client_disconnected_can_be_called_without_queue, test::small_temperature_service_with_response<> )\n{\n    this->client_disconnected( connection );\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "tests/att/read_blob_tests.cpp",
    "content": "#define BOOST_TEST_MODULE\n#include <boost/test/included/unit_test.hpp>\n\n#include \"test_servers.hpp\"\n\nBOOST_AUTO_TEST_SUITE( read_blob_errors )\n\nBOOST_FIXTURE_TEST_CASE( pdu_to_small, test::small_temperature_service_with_response<> )\n{\n    BOOST_CHECK( check_error_response( { 0x0C, 0x02, 0x00, 0x00 }, 0x0C, 0x0000, 0x04 ) );\n}\n\nBOOST_FIXTURE_TEST_CASE( pdu_to_large, test::small_temperature_service_with_response<> )\n{\n    BOOST_CHECK( check_error_response( { 0x0C, 0x02, 0x00, 0x00, 0x00, 0x00 }, 0x0C, 0x0000, 0x04 ) );\n}\n\nBOOST_FIXTURE_TEST_CASE( no_such_handle, test::small_temperature_service_with_response<> )\n{\n    BOOST_CHECK( check_error_response( { 0x0C, 0x17, 0xAA, 0x00, 0x00 }, 0x0C, 0xAA17, 0x01 ) );\n    BOOST_CHECK( check_error_response( { 0x0C, 0x04, 0x00, 0x00, 0x00 }, 0x0C, 0x0004, 0x01 ) );\n}\n\nBOOST_FIXTURE_TEST_CASE( invalid_handle, test::small_temperature_service_with_response<> )\n{\n    BOOST_CHECK( check_error_response( { 0x0C, 0x00, 0x00, 0x00, 0x00 }, 0x0C, 0x0000, 0x01 ) );\n}\n\nchar blob[ 100 ] = {};\n\ntypedef bluetoe::server<\n    bluetoe::service<\n        bluetoe::service_uuid< 0x8C8B4094, 0x0DE2, 0x499F, 0xA28A, 0x4EED5BC73CA9 >,\n        bluetoe::characteristic<\n            bluetoe::characteristic_uuid< 0x8C8B4094, 0x0DE2, 0x499F, 0xA28A, 0x4EED5BC73CAA >,\n            bluetoe::bind_characteristic_value< decltype( blob ), &blob >,\n            bluetoe::no_read_access\n        >\n    >\n> unreadable_blob_server;\n\n\nBOOST_FIXTURE_TEST_CASE( not_readable, test::request_with_reponse< unreadable_blob_server > )\n{\n    BOOST_CHECK( check_error_response( { 0x0C, 0x03, 0x00, 0x00, 0x00 }, 0x0C, 0x0003, 0x02 ) );\n}\n\nBOOST_FIXTURE_TEST_CASE( read_behind_end, test::small_temperature_service_with_response<> )\n{\n    BOOST_CHECK( check_error_response( { 0x0C, 0x03, 0x00, 0x05, 0x00 }, 0x0C, 0x0003, 0x07 ) );\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE( read_blob )\n\nstatic const char const_blob[ 50 ] = {\n    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,\n    0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19,\n    0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29,\n    0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,\n    0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49\n};\n\ntypedef bluetoe::server<\n    bluetoe::service<\n        bluetoe::service_uuid< 0x8C8B4094, 0x0DE2, 0x499F, 0xA28A, 0x4EED5BC73CA9 >,\n        bluetoe::characteristic<\n            bluetoe::attribute_handle< 0x0815 >,\n            bluetoe::characteristic_uuid< 0x8C8B4094, 0x0DE2, 0x499F, 0xA28A, 0x4EED5BC73CAA >,\n            bluetoe::bind_characteristic_value< decltype( const_blob ), &const_blob >\n        >\n    >\n> blob_server;\n\nBOOST_FIXTURE_TEST_CASE( read_starting_at_0, test::request_with_reponse< blob_server > )\n{\n    l2cap_input( { 0x0C, 0x16, 0x08, 0x00, 0x00 } );\n    expected_result( {\n        0x0D,\n        0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,\n        0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19,\n        0x20, 0x21\n    } );\n}\n\nBOOST_FIXTURE_TEST_CASE( read_starting_at_50, test::request_with_reponse< blob_server > )\n{\n    l2cap_input( { 0x0C, 0x16, 0x08, 0x32, 0x00 } );\n    expected_result( { 0x0D } );\n}\n\nBOOST_FIXTURE_TEST_CASE( read_starting_at_10, test::request_with_reponse< blob_server > )\n{\n    l2cap_input( { 0x0C, 0x16, 0x08, 0x0A, 0x00 } );\n    expected_result( {\n        0x0D,\n        0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19,\n        0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29,\n        0x30, 0x31\n    } );\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "tests/att/read_by_group_type_tests.cpp",
    "content": "#define BOOST_TEST_MODULE\n#include <boost/test/included/unit_test.hpp>\n\n#include <test_servers.hpp>\n#include <test_services.hpp>\n\nBOOST_AUTO_TEST_SUITE( read_by_group_type_errors )\n\nBOOST_FIXTURE_TEST_CASE( start_handle_zero, test::small_temperature_service_with_response<> )\n{\n    BOOST_CHECK( check_error_response( { 0x10, 0x00, 0x00, 0xff, 0xff, 0x00, 0x28 }, 0x10, 0x0000, 0x01 ) );\n}\n\nBOOST_FIXTURE_TEST_CASE( start_handle_greater_than_end_handle, test::small_temperature_service_with_response<> )\n{\n    BOOST_CHECK( check_error_response( { 0x10, 0x05, 0x00, 0x04, 0x00, 0x00, 0x28 }, 0x10, 0x0005, 0x01 ) );\n}\n\nBOOST_FIXTURE_TEST_CASE( invalid_request_size, test::small_temperature_service_with_response<> )\n{\n    BOOST_CHECK( check_error_response( { 0x10, 0x05, 0x00, 0x05, 0x00 }, 0x10, 0x0000, 0x04 ) );\n}\n\nBOOST_FIXTURE_TEST_CASE( handle_out_of_range, test::small_temperature_service_with_response<> )\n{\n    BOOST_CHECK( check_error_response( { 0x10, 0x40, 0x00, 0xff, 0xff, 0x00, 0x28 }, 0x10, 0x0040, 0x0A ) );\n}\n\nBOOST_FIXTURE_TEST_CASE( unsupprorted_group_type, test::small_temperature_service_with_response<> )\n{\n    // every type but the «Primary Service» is invalid for GATT\n    BOOST_CHECK( check_error_response( { 0x10, 0x01, 0x00, 0xff, 0xff, 0x01, 0x28 }, 0x10, 0x0001, 0x10 ) );\n}\n\nBOOST_FIXTURE_TEST_CASE( unsupprorted_group_type_128bit, test::small_temperature_service_with_response<> )\n{\n    // every type but the «Primary Service» is invalid for GATT\n    BOOST_CHECK( check_error_response(\n        {\n            0x10, 0x01, 0x00, 0xff, 0xff,\n            0x00, 0x01, 0x02, 0x03,\n            0x04, 0x05, 0x06, 0x06,\n            0x08, 0x09, 0x0a, 0x0b,\n            0x0c, 0x0d, 0x0e, 0x0f\n        }, 0x10, 0x0001, 0x10 ) );\n}\n\nBOOST_FIXTURE_TEST_CASE( request_out_of_range, test::small_temperature_service_with_response<> )\n{\n    BOOST_CHECK( check_error_response(\n        { 0x10, 0x02, 0x00, 0xff, 0xff, 0x00, 0x28 }, 0x10, 0x0002, 0x0a ) );\n\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE( discover_primary_services )\n\nBOOST_FIXTURE_TEST_CASE( single_service, test::small_temperature_service_with_response<> )\n{\n    l2cap_input( { 0x10, 0x01, 0x00, 0xff, 0xff, 0x00, 0x28 } );\n\n    static const std::uint8_t expected_result[] = {\n        0x11, 0x14,                 // response code, size\n        0x01, 0x00, 0x03, 0x00,     // 0x0001 - 0x0003\n        0xA9, 0x3C, 0xC7, 0x5B,     // 128 bit UUID\n        0xED, 0x4E, 0x8A, 0xA2,\n        0x9F, 0x49, 0xE2, 0x0D,\n        0x94, 0x40, 0x8B, 0x8C\n    };\n\n    BOOST_CHECK_EQUAL_COLLECTIONS( &response[ 0 ], &response[ response_size ], std::begin( expected_result ), std::end( expected_result ) );\n}\n\ntypedef bluetoe::server<\n    test::global_temperature_service,\n    test::service_with_3_characteristics,\n    test::cycling_speed_and_cadence_service\n> server_with_3_characteristics;\n\ntypedef test::request_with_reponse< server_with_3_characteristics, 100 > request_with_reponse_server_with_3_characteristics_100;\n\nBOOST_FIXTURE_TEST_CASE( different_attribute_data_size, request_with_reponse_server_with_3_characteristics_100 )\n{\n    l2cap_input( { 0x10, 0x01, 0x00, 0xff, 0xff, 0x00, 0x28 } );\n\n    static const std::uint8_t expected_result[] = {\n        0x11, 0x14,                 // response code, size\n        0x01, 0x00, 0x03, 0x00,     // handle 0x0001 - 0x0003\n        0x2A, 0xD9, 0x91, 0x11,     // service_uuid global_temperature_service\n        0xAB, 0x5B, 0x58, 0xB0,\n        0x3B, 0x4F, 0x50, 0x44,\n        0x52, 0x6E, 0x42, 0xF0,\n        0x04, 0x00, 0x0A, 0x00,     // handle 0x0004 - 0x000A\n        0xA9, 0x3C, 0xC7, 0x5B,\n        0xED, 0x4E, 0x8A, 0xA2,\n        0x9F, 0x49, 0xE2, 0x0D,\n        0x94, 0x40, 0x8B, 0x8C\n    };\n\n    BOOST_CHECK_EQUAL_COLLECTIONS( &response[ 0 ], &response[ response_size ], std::begin( expected_result ), std::end( expected_result ) );\n}\n\ntypedef test::request_with_reponse< server_with_3_characteristics, 41 > request_with_reponse_server_with_3_characteristics_41;\n\nBOOST_FIXTURE_TEST_CASE( output_to_small_for_more_than_one_service, request_with_reponse_server_with_3_characteristics_41 )\n{\n    l2cap_input( { 0x10, 0x01, 0x00, 0xff, 0xff, 0x00, 0x28 } );\n\n    static const std::uint8_t expected_result[] = {\n        0x11, 0x14,                 // response code, size\n        0x01, 0x00, 0x03, 0x00,     // handle 0x0001 - 0x0003\n        0x2A, 0xD9, 0x91, 0x11,     // service_uuid global_temperature_service\n        0xAB, 0x5B, 0x58, 0xB0,\n        0x3B, 0x4F, 0x50, 0x44,\n        0x52, 0x6E, 0x42, 0xF0\n    };\n\n    BOOST_CHECK_EQUAL_COLLECTIONS( &response[ 0 ], &response[ response_size ], std::begin( expected_result ), std::end( expected_result ) );\n}\n\ntypedef bluetoe::server<\n    test::global_temperature_service,\n    test::cycling_speed_and_cadence_service,\n    test::service_with_3_characteristics,\n    bluetoe::no_gap_service_for_gatt_servers\n> server_with_16bit_characteristics_in_the_middle;\n\ntypedef test::request_with_reponse< server_with_16bit_characteristics_in_the_middle, 100 > server_with_16bit_characteristics_in_the_middle_100;\n\n/**\n * #53 Read by Group Type Request should not return lists that contain gaps\n *\n * In order for the GATT Discover All Primary Services procedure to work correctly,\n * Read by Group Type Request should not return lists that contains gaps.\n * Group Type Request is used to discover services, and can return only services of\n * the same UUID length. If the server contains mixed 16-bit and 128-bit UUIDs,\n * the server shall not assemble lists where two services are contain,\n * where a service of the other kind would be in the middle.\n *\n * For example, a server containing a 16-bit UUID service, followed by a 128-bit UUID service,\n * followed by a 16-bit UUID service again, the server should not put both 16-bit UUID\n * services into one Read by Group Type Response.\n */\n\nBOOST_FIXTURE_TEST_CASE( different_attribute_data_size_without_gap, server_with_16bit_characteristics_in_the_middle_100 )\n{\n    l2cap_input( { 0x10, 0x01, 0x00, 0xff, 0xff, 0x00, 0x28 } );\n\n    static const std::uint8_t expected_result_1[] = {\n        0x11, 0x14,                 // response code, size\n        0x01, 0x00, 0x03, 0x00,     // handle 0x0001 - 0x0003\n        0x2A, 0xD9, 0x91, 0x11,     // service_uuid global_temperature_service\n        0xAB, 0x5B, 0x58, 0xB0,\n        0x3B, 0x4F, 0x50, 0x44,\n        0x52, 0x6E, 0x42, 0xF0,\n    };\n\n    BOOST_CHECK_EQUAL_COLLECTIONS( &response[ 0 ], &response[ response_size ], std::begin( expected_result_1 ), std::end( expected_result_1 ) );\n\n    l2cap_input( { 0x10, 0x04, 0x00, 0xff, 0xff, 0x00, 0x28 } );\n\n    static const std::uint8_t expected_result_2[] = {\n        0x11, 0x6,                  // response code, size\n        0x04, 0x00, 0x08, 0x00,     // handle 0x0004 - 0x000A\n        0x16, 0x18                  // Cycling Speed and Cadence\n    };\n\n    BOOST_CHECK_EQUAL_COLLECTIONS( &response[ 0 ], &response[ response_size ], std::begin( expected_result_2 ), std::end( expected_result_2 ) );\n\n    l2cap_input( { 0x10, 0x09, 0x00, 0xff, 0xff, 0x00, 0x28 } );\n\n    static const std::uint8_t expected_result_3[] = {\n        0x11, 0x14,                 // response code, size\n        0x09, 0x00, 0x0F, 0x00,     // handle 0x0001 - 0x0003\n        0xA9, 0x3C, 0xC7, 0x5B,     // 128 bit UUID\n        0xED, 0x4E, 0x8A, 0xA2,\n        0x9F, 0x49, 0xE2, 0x0D,\n        0x94, 0x40, 0x8B, 0x8C\n    };\n\n    BOOST_CHECK_EQUAL_COLLECTIONS( &response[ 0 ], &response[ response_size ], std::begin( expected_result_3 ), std::end( expected_result_3 ) );\n\n    l2cap_input( { 0x10, 0x10, 0x00, 0xff, 0xff, 0x00, 0x28 } );\n\n    static const std::uint8_t expected_result_4[] = {\n        0x01,                       // Error Response\n        0x10,                       // request opcode\n        0x10, 0x00,                 // request handle\n        0x0A                        // «Attribute Not Found»\n    };\n\n    BOOST_CHECK_EQUAL_COLLECTIONS( &response[ 0 ], &response[ response_size ], std::begin( expected_result_4 ), std::end( expected_result_4 ) );\n}\n\nBOOST_FIXTURE_TEST_CASE( read_16bit_uuid_in_gap, test::request_with_reponse< server_with_16bit_characteristics_in_the_middle > )\n{\n    l2cap_input( { 0x10, 0x04, 0x00, 0xff, 0xff, 0x00, 0x28 } );\n\n    static const std::uint8_t expected_result[] = {\n        0x11, 0x06,                 // response code, size\n        0x04, 0x00, 0x08, 0x00,     // handle 0x0001 - 0x0003\n        0x16, 0x18                  // service_uuid cycling_speed_and_cadence_service\n    };\n\n    BOOST_CHECK_EQUAL_COLLECTIONS( &response[ 0 ], &response[ response_size ], std::begin( expected_result ), std::end( expected_result ) );\n}\n\ntypedef bluetoe::server<\n    test::cycling_speed_and_cadence_service,\n    test::cycling_speed_and_cadence_service,\n    test::cycling_speed_and_cadence_service,\n    test::cycling_speed_and_cadence_service\n> server_with_4_bicycles;\n\nBOOST_FIXTURE_TEST_CASE( output_to_small_to_read_all_services, test::request_with_reponse< server_with_4_bicycles > )\n{\n    l2cap_input( { 0x10, 0x01, 0x00, 0xff, 0xff, 0x00, 0x28 } );\n\n    static const std::uint8_t expected_result[] = {\n        0x11, 0x06,                 // response code, size\n        0x01, 0x00, 0x05, 0x00,\n        0x16, 0x18,\n        0x06, 0x00, 0x0A, 0x00,\n        0x16, 0x18,\n        0x0B, 0x00, 0x0F, 0x00,\n        0x16, 0x18\n    };\n\n    BOOST_CHECK_EQUAL_COLLECTIONS( &response[ 0 ], &response[ response_size ], std::begin( expected_result ), std::end( expected_result ) );\n}\n\nusing server_with_fixed_handles = bluetoe::server<\n    bluetoe::service<\n        bluetoe::attribute_handle< 0x0100 >,\n        bluetoe::service_uuid16< 0x1801 >,\n        bluetoe::characteristic<\n            bluetoe::attribute_handles< 0x1000, 0x2000, 0x3000 >,\n            bluetoe::characteristic_uuid16< 0x2A05 >,\n            bluetoe::indicate,\n            bluetoe::fixed_uint32_value< 0xFFFF0001 >\n        >\n    >,\n    test::cycling_speed_and_cadence_service,\n    bluetoe::no_gap_service_for_gatt_servers\n>;\n\nBOOST_FIXTURE_TEST_CASE( discover_services_with_fixed_handles, test::request_with_reponse< server_with_fixed_handles > )\n{\n    l2cap_input( { 0x10, 0x01, 0x00, 0xff, 0xff, 0x00, 0x28 } );\n\n    static const std::uint8_t expected_result[] = {\n        0x11, 0x06,                 // response code, size\n        0x00, 0x01, 0x00, 0x30,\n        0x01, 0x18,\n        0x01, 0x30, 0x05, 0x30,\n        0x16, 0x18\n    };\n\n    BOOST_CHECK_EQUAL_COLLECTIONS( &response[ 0 ], &response[ response_size ], std::begin( expected_result ), std::end( expected_result ) );\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "tests/att/read_by_type_tests.cpp",
    "content": "#define BOOST_TEST_MODULE\n#include <boost/test/included/unit_test.hpp>\n\n#include <test_servers.hpp>\n#include <test_services.hpp>\n\nBOOST_AUTO_TEST_SUITE( read_by_type_errors )\n\nBOOST_FIXTURE_TEST_CASE( invalid_request_size, test::small_temperature_service_with_response<> )\n{\n    BOOST_CHECK( check_error_response( { 0x08, 0x01, 0x00, 0xff, 0xff, 0x03 }, 0x08, 0x0000, 0x04 ) );\n    BOOST_CHECK( check_error_response( { 0x08, 0x01, 0x00, 0xff, 0xff, 0x03, 0x04, 0x05, 0x06 }, 0x08, 0x0000, 0x04 ) );\n}\n\nBOOST_FIXTURE_TEST_CASE( start_handle_zero, test::small_temperature_service_with_response<> )\n{\n    BOOST_CHECK( check_error_response( { 0x08, 0x00, 0x00, 0xff, 0xff, 0x03, 0x28 }, 0x08, 0x0000, 0x01 ) );\n}\n\nBOOST_FIXTURE_TEST_CASE( start_handle_greater_than_end_handle, test::small_temperature_service_with_response<> )\n{\n    BOOST_CHECK( check_error_response( { 0x08, 0x05, 0x00, 0x04, 0x00, 0x03, 0x28 }, 0x08, 0x0005, 0x01 ) );\n}\n\nBOOST_FIXTURE_TEST_CASE( handle_out_of_range, test::small_temperature_service_with_response<> )\n{\n    BOOST_CHECK( check_error_response( { 0x08, 0x40, 0x00, 0xff, 0xff, 0x00, 0x28 }, 0x08, 0x0040, 0x0A ) );\n}\n\nBOOST_FIXTURE_TEST_CASE( no_such_type, test::small_temperature_service_with_response<> )\n{\n    BOOST_CHECK( check_error_response( { 0x08, 0x01, 0x00, 0xff, 0xff, 0xab, 0xcd }, 0x08, 0x0001, 0x0A ) );\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE( read_by_type )\n\nBOOST_FIXTURE_TEST_CASE( read_a_single_attribute, test::small_temperature_service_with_response<> )\n{\n    l2cap_input( { 0x08, 0x01, 0x00, 0xff, 0xff, 0x03, 0x28 } );\n\n    static const std::uint8_t expected_result[] = {\n        0x09, 0x15,                 // response code, size = 2 for handle and 19 for attribute value (Properties, Value Handle + UUID)\n        0x02, 0x00,                 // attribute handle\n        0x02,                       // Characteristic Properties (read)\n        0x03, 0x00,                 // Characteristic Value Handle\n        0xAA, 0x3C, 0xC7, 0x5B,     // Characteristic UUID\n        0xED, 0x4E, 0x8A, 0xA2,\n        0x9F, 0x49, 0xE2, 0x0D,\n        0x94, 0x40, 0x8B, 0x8C\n    };\n\n    BOOST_CHECK_EQUAL_COLLECTIONS( &response[ 0 ], &response[ response_size ], std::begin( expected_result ), std::end( expected_result ) );\n}\n\nBOOST_FIXTURE_TEST_CASE( read_a_single_attribute_using_128bit_uuid, test::small_temperature_service_with_response<> )\n{\n    l2cap_input( {\n        0x08, 0x01, 0x00, 0xff, 0xff,\n        0xFB, 0x34, 0x9B, 0x5F,     // 16 bit UUID extended to 128 bit\n        0x80, 0x00, 0x00, 0x80,\n        0x00, 0x10, 0x00, 0x00,\n        0x03, 0x28, 0x00, 0x00 } );\n\n    static const std::uint8_t expected_result[] = {\n        0x09, 0x15,                 // response code, size = 2 for handle and 19 for attribute value (Properties, Value Handle + UUID)\n        0x02, 0x00,                 // attribute handle\n        0x02,                       // Characteristic Properties (read)\n        0x03, 0x00,                 // Characteristic Value Handle\n        0xAA, 0x3C, 0xC7, 0x5B,     // Characteristic UUID\n        0xED, 0x4E, 0x8A, 0xA2,\n        0x9F, 0x49, 0xE2, 0x0D,\n        0x94, 0x40, 0x8B, 0x8C\n    };\n\n    BOOST_CHECK_EQUAL_COLLECTIONS( &response[ 0 ], &response[ response_size ], std::begin( expected_result ), std::end( expected_result ) );\n}\n\ntypedef test::request_with_reponse< test::three_apes_service, 100 > request_with_reponse_three_apes_service_100;\n\nBOOST_FIXTURE_TEST_CASE( read_multiple_attributes, request_with_reponse_three_apes_service_100 )\n{\n    l2cap_input( { 0x08, 0x01, 0x00, 0xff, 0xff, 0x03, 0x28 } );\n\n    static const std::uint8_t expected_result[] = {\n        0x09, 0x15,                 // response code, size = 2 for handle and 19 for attribute value (Properties, Value Handle + UUID)\n        0x02, 0x00,                 // attribute handle\n        0x0A,                       // Characteristic Properties (read + write)\n        0x03, 0x00,                 // Characteristic Value Handle\n        0xAA, 0x3C, 0xC7, 0x5B,     // Characteristic UUID\n        0xED, 0x4E, 0x8A, 0xA2,\n        0x9F, 0x49, 0xE2, 0x0D,\n        0x94, 0x40, 0x8B, 0x8C,\n        0x04, 0x00,                 // attribute handle\n        0x0A,                       // Characteristic Properties (read + write)\n        0x05, 0x00,                 // Characteristic Value Handle\n        0xAB, 0x3C, 0xC7, 0x5B,     // Characteristic UUID\n        0xED, 0x4E, 0x8A, 0xA2,\n        0x9F, 0x49, 0xE2, 0x0D,\n        0x94, 0x40, 0x8B, 0x8C,\n        0x06, 0x00,                 // attribute handle\n        0x0A,                       // Characteristic Properties (read + write)\n        0x07, 0x00,                 // Characteristic Value Handle\n        0xAC, 0x3C, 0xC7, 0x5B,     // Characteristic UUID\n        0xED, 0x4E, 0x8A, 0xA2,\n        0x9F, 0x49, 0xE2, 0x0D,\n        0x94, 0x40, 0x8B, 0x8C\n    };\n\n    BOOST_CHECK_EQUAL_COLLECTIONS( &response[ 0 ], &response[ response_size ], std::begin( expected_result ), std::end( expected_result ) );\n}\n\ntypedef test::request_with_reponse< test::three_apes_service, 50 > request_with_reponse_three_apes_service_50;\n\nBOOST_FIXTURE_TEST_CASE( read_multiple_attributes_buffer_to_small, request_with_reponse_three_apes_service_50 )\n{\n    l2cap_input( { 0x08, 0x01, 0x00, 0xff, 0xff, 0x03, 0x28 } );\n\n    static const std::uint8_t expected_result[] = {\n        0x09, 0x15,                 // response code, size = 2 for handle and 19 for attribute value (Properties, Value Handle + UUID)\n        0x02, 0x00,                 // attribute handle\n        0x0A,                       // Characteristic Properties (read + write)\n        0x03, 0x00,                 // Characteristic Value Handle\n        0xAA, 0x3C, 0xC7, 0x5B,     // Characteristic UUID\n        0xED, 0x4E, 0x8A, 0xA2,\n        0x9F, 0x49, 0xE2, 0x0D,\n        0x94, 0x40, 0x8B, 0x8C,\n        0x04, 0x00,                 // attribute handle\n        0x0A,                       // Characteristic Properties (read + write)\n        0x05, 0x00,                 // Characteristic Value Handle\n        0xAB, 0x3C, 0xC7, 0x5B,     // Characteristic UUID\n        0xED, 0x4E, 0x8A, 0xA2,\n        0x9F, 0x49, 0xE2, 0x0D,\n        0x94, 0x40, 0x8B, 0x8C\n    };\n\n    BOOST_CHECK_EQUAL_COLLECTIONS( &response[ 0 ], &response[ response_size ], std::begin( expected_result ), std::end( expected_result ) );\n}\n\nBOOST_FIXTURE_TEST_CASE( read_multiple_attributes_buffer_in_range, request_with_reponse_three_apes_service_100 )\n{\n    l2cap_input( { 0x08, 0x01, 0x00, 0x04, 0x00, 0x03, 0x28 } );\n\n    static const std::uint8_t expected_result[] = {\n        0x09, 0x15,                 // response code, size = 2 for handle and 19 for attribute value (Properties, Value Handle + UUID)\n        0x02, 0x00,                 // attribute handle\n        0x0A,                       // Characteristic Properties (read + write)\n        0x03, 0x00,                 // Characteristic Value Handle\n        0xAA, 0x3C, 0xC7, 0x5B,     // Characteristic UUID\n        0xED, 0x4E, 0x8A, 0xA2,\n        0x9F, 0x49, 0xE2, 0x0D,\n        0x94, 0x40, 0x8B, 0x8C,\n        0x04, 0x00,                 // attribute handle\n        0x0A,                       // Characteristic Properties (read + write)\n        0x05, 0x00,                 // Characteristic Value Handle\n        0xAB, 0x3C, 0xC7, 0x5B,     // Characteristic UUID\n        0xED, 0x4E, 0x8A, 0xA2,\n        0x9F, 0x49, 0xE2, 0x0D,\n        0x94, 0x40, 0x8B, 0x8C\n    };\n\n    BOOST_CHECK_EQUAL_COLLECTIONS( &response[ 0 ], &response[ response_size ], std::begin( expected_result ), std::end( expected_result ) );\n}\n\ntypedef bluetoe::server<\n    bluetoe::service<\n        bluetoe::service_uuid< 0x8C8B4094, 0x0DE2, 0x499F, 0xA28A, 0x4EED5BC73CA9 >,\n        bluetoe::characteristic<\n            bluetoe::characteristic_uuid< 0x8C8B4094, 0x0DE2, 0x499F, 0xA28A, 0x4EED5BC73CAA >,\n            bluetoe::bind_characteristic_value< std::uint8_t, &test::ape1 >\n        >,\n        bluetoe::characteristic<\n            bluetoe::characteristic_uuid16< 0x0815 >,\n            bluetoe::bind_characteristic_value< std::uint8_t, &test::ape2 >\n        >,\n        bluetoe::characteristic<\n            bluetoe::characteristic_uuid< 0x8C8B4094, 0x0DE2, 0x499F, 0xA28A, 0x4EED5BC73CAC >,\n            bluetoe::bind_characteristic_value< std::uint8_t, &test::ape3 >\n        >\n    >\n> server_with_16bit_uuid_in_the_middle;\n\ntypedef test::request_with_reponse< server_with_16bit_uuid_in_the_middle, 200 > r_and_r_with_server_with_16bit_uuid_in_the_middle_100;\n\nBOOST_FIXTURE_TEST_CASE( read_multiple_attributes_within_mixed_size, r_and_r_with_server_with_16bit_uuid_in_the_middle_100 )\n{\n    l2cap_input( { 0x08, 0x01, 0x00, 0xff, 0xff, 0x03, 0x28 } );\n\n    static const std::uint8_t expected_result[] = {\n        0x09, 0x15,                 // response code, size = 2 for handle and 19 for attribute value (Properties, Value Handle + UUID)\n        0x02, 0x00,                 // attribute handle\n        0x0A,                       // Characteristic Properties (read + write)\n        0x03, 0x00,                 // Characteristic Value Handle\n        0xAA, 0x3C, 0xC7, 0x5B,     // Characteristic UUID\n        0xED, 0x4E, 0x8A, 0xA2,\n        0x9F, 0x49, 0xE2, 0x0D,\n        0x94, 0x40, 0x8B, 0x8C,\n        0x06, 0x00,                 // attribute handle\n        0x0A,                       // Characteristic Properties (read + write)\n        0x07, 0x00,                 // Characteristic Value Handle\n        0xAC, 0x3C, 0xC7, 0x5B,     // Characteristic UUID\n        0xED, 0x4E, 0x8A, 0xA2,\n        0x9F, 0x49, 0xE2, 0x0D,\n        0x94, 0x40, 0x8B, 0x8C\n    };\n\n    BOOST_CHECK_EQUAL_COLLECTIONS( &response[ 0 ], &response[ response_size ], std::begin( expected_result ), std::end( expected_result ) );\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE( read_by_type_seen_in_the_wild )\n\nstd::uint32_t temperature_value = 0x12345678;\nstatic constexpr char server_name[] = \"Temperature\";\nstatic constexpr char char_name[] = \"Temperature Value\";\n\ntypedef bluetoe::server<\n    bluetoe::server_name< server_name >,\n    bluetoe::service<\n        bluetoe::service_uuid< 0x8C8B4094, 0x0000, 0x499F, 0xA28A, 0x4EED5BC73CA9 >,\n        bluetoe::characteristic<\n            bluetoe::characteristic_name< char_name >,\n            bluetoe::characteristic_uuid< 0x8C8B4094, 0x0000, 0x499F, 0xA28A, 0x4EED5BC73CAA >,\n            bluetoe::bind_characteristic_value< decltype( temperature_value ), &temperature_value >\n        >\n    >\n> small_temperature_service;\n\nBOOST_FIXTURE_TEST_CASE( should_find_the_device_name_characteristic, test::request_with_reponse< small_temperature_service > )\n{\n    l2cap_input( { 0x02, 0x68, 0x00 } );\n    expected_result( { 0x03, 0x17, 0x00 } );\n\n    l2cap_input( { 0x08, 0x01, 0x00, 0xff, 0xff, 0x00, 0x2a } );\n    BOOST_REQUIRE( response_size > 0 );\n    BOOST_CHECK_EQUAL( response[ 0 ], 0x09 );\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "tests/att/read_multiple_tests.cpp",
    "content": "#define BOOST_TEST_MODULE\n#include <boost/test/included/unit_test.hpp>\n\n#include \"test_servers.hpp\"\n\nBOOST_AUTO_TEST_SUITE( read_multiple_errors )\n\nBOOST_FIXTURE_TEST_CASE( pdu_to_small, test::small_temperature_service_with_response<> )\n{\n    BOOST_CHECK( check_error_response( { 0x0E, 0x02, 0x00 }, 0x0E, 0x0000, 0x04 ) );\n}\n\nBOOST_FIXTURE_TEST_CASE( pdu_half_an_handle, test::small_temperature_service_with_response<> )\n{\n    BOOST_CHECK( check_error_response( { 0x0E, 0x02, 0x00, 0x03, 0x00, 0x04 }, 0x0E, 0x0000, 0x04 ) );\n}\n\nBOOST_FIXTURE_TEST_CASE( the_first_handle_is_invalid, test::small_temperature_service_with_response<> )\n{\n    BOOST_CHECK( check_error_response( { 0x0E, 0x00, 0x00, 0x03, 0x00, 0x04, 0x00 }, 0x0E, 0x0000, 0x01 ) );\n}\n\nBOOST_FIXTURE_TEST_CASE( the_second_handle_is_invalid, test::small_temperature_service_with_response<> )\n{\n    BOOST_CHECK( check_error_response( { 0x0E, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00 }, 0x0E, 0x0000, 0x01 ) );\n}\n\nBOOST_FIXTURE_TEST_CASE( the_first_handle_is_unknown, test::small_temperature_service_with_response<> )\n{\n    BOOST_CHECK( check_error_response( { 0x0E, 0x02, 0x80, 0x03, 0x00, 0x04, 0x00 }, 0x0E, 0x8002, 0x01 ) );\n}\n\nBOOST_FIXTURE_TEST_CASE( the_second_handle_is_unknown, test::small_temperature_service_with_response<> )\n{\n    BOOST_CHECK( check_error_response( { 0x0E, 0x02, 0x00, 0x03, 0x00, 0xf4, 0xff }, 0x0E, 0xfff4, 0x01 ) );\n}\n\ntypedef bluetoe::server<\n    bluetoe::service<\n        bluetoe::service_uuid< 0x8C8B4094, 0x0DE2, 0x499F, 0xA28A, 0x4EED5BC73CA9 >,\n        bluetoe::characteristic<\n            bluetoe::characteristic_uuid< 0x8C8B4094, 0x0DE2, 0x499F, 0xA28A, 0x4EED5BC73CAA >,\n            bluetoe::bind_characteristic_value< decltype( test::temperature_value ), &test::temperature_value >,\n            bluetoe::no_read_access\n        >\n    >\n> unreadable_server;\n\n\nBOOST_FIXTURE_TEST_CASE( first_attribute_not_readable, test::request_with_reponse< unreadable_server > )\n{\n    BOOST_CHECK( check_error_response( { 0x0E, 0x03, 0x00, 0x02, 0x00 }, 0x0E, 0x0003, 0x02 ) );\n}\n\nBOOST_FIXTURE_TEST_CASE( last_attribute_not_readable, test::request_with_reponse< unreadable_server > )\n{\n    BOOST_CHECK( check_error_response( { 0x0E, 0x02, 0x00, 0x03, 0x00 }, 0x0E, 0x0003, 0x02 ) );\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE( read_multiple )\n\nBOOST_FIXTURE_TEST_CASE( read_two_attributes, test::small_temperature_service_with_response< > )\n{\n    l2cap_input( { 0x0E, 0x02, 0x00, 0x03, 0x00 } );\n\n    expected_result( {\n        0x0F,                                           // opcode\n        0x02, 0x03, 0x00,                               // Characteristic Declaration\n        0xAA, 0x3C, 0xC7, 0x5B, 0xED, 0x4E, 0x8A, 0xA2,\n        0x9F, 0x49, 0xE2, 0x0D, 0x94, 0x40, 0x8B, 0x8C,\n        0x04, 0x01                                      // Characteristic Value Declaration\n    } );\n}\n\nBOOST_FIXTURE_TEST_CASE( read_all_attributes_last_attribute_clipped, test::small_temperature_service_with_response< > )\n{\n    l2cap_input( { 0x0E, 0x02, 0x00, 0x03, 0x00, 0x01, 0x00 } );\n    expected_result( {\n        0x0F,                                           // opcode\n        0x02, 0x03, 0x00,                               // Characteristic Declaration\n        0xAA, 0x3C, 0xC7, 0x5B, 0xED, 0x4E, 0x8A, 0xA2,\n        0x9F, 0x49, 0xE2, 0x0D, 0x94, 0x40, 0x8B, 0x8C,\n        0x04, 0x01,                                     // Characteristic Value Declaration\n        0xA9                                            // Primary Service, clipped at the mtu of 23\n    } );\n}\n\n// if the mtu is small enough that already the last but one attributes gets clipped, there should be a valid response\nBOOST_FIXTURE_TEST_CASE( already_the_last_but_one_attribute_gets_clipped, test::request_with_reponse< test::three_apes_service > )\n{\n    // read the Primary Service, the first and second Characteristic Declaration\n    l2cap_input( { 0x0E, 0x01, 0x00, 0x02, 0x00, 0x04, 0x00 } );\n    expected_result( {\n        0x0F,                                           // opcode\n        0xA9, 0x3C, 0xC7, 0x5B, 0xED, 0x4E, 0x8A, 0xA2, // Primary Service\n        0x9F, 0x49, 0xE2, 0x0D, 0x94, 0x40, 0x8B, 0x8C,\n        0x0A, 0x03, 0x00,                               // first Characteristic Declaration; already clipped\n        0xAA, 0x3C, 0xC7\n                                                        // second Characteristic...\n    } );\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE( read_multiple_fixed )\n\n    using server = bluetoe::server<\n        bluetoe::service<\n            bluetoe::service_uuid< 0x8C8B4094, 0x0DE2, 0x499F, 0xA28A, 0x4EED5BC73CA9 >,\n            bluetoe::characteristic<\n                bluetoe::fixed_uint8_value< 0x10 >\n            >,\n            bluetoe::characteristic<\n                bluetoe::attribute_handles< 0x1213, 0x1314 >,\n                bluetoe::fixed_uint8_value< 0x20 >,\n                bluetoe::notify\n            >\n        >\n    >;\n\n    BOOST_FIXTURE_TEST_CASE( read_all_values_and_cccds, test::request_with_reponse< server > )\n    {\n        l2cap_input( {\n            0x0E,\n            0x03, 0x00,\n            0x14, 0x13,\n            0x15, 0x13\n        } );\n\n        expected_result( {\n            0x0F,\n            0x10,\n            0x20,\n            0x00, 0x00\n        } );\n\n    }\n\n    BOOST_FIXTURE_TEST_CASE( invalid_handle, test::request_with_reponse< server > )\n    {\n        l2cap_input( {\n            0x0E,\n            0x03, 0x00,\n            0x14, 0x13,\n            0x50, 0x12\n        } );\n\n        expected_result( {\n            0x01,\n            0x0E,\n            0x50, 0x12,\n            0x01\n        } );\n\n    }\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "tests/att/read_tests.cpp",
    "content": "#define BOOST_TEST_MODULE\n#include <boost/test/included/unit_test.hpp>\n\n#include \"test_servers.hpp\"\n\nBOOST_AUTO_TEST_SUITE( read_by_type_errors )\n\nBOOST_FIXTURE_TEST_CASE( pdu_to_small, test::small_temperature_service_with_response<> )\n{\n    BOOST_CHECK( check_error_response( { 0x0A, 0x02 }, 0x0A, 0x0000, 0x04 ) );\n}\n\nBOOST_FIXTURE_TEST_CASE( pdu_to_large, test::small_temperature_service_with_response<> )\n{\n    BOOST_CHECK( check_error_response( { 0x0A, 0x02, 0x00, 0xab }, 0x0A, 0x0000, 0x04 ) );\n}\n\nBOOST_FIXTURE_TEST_CASE( no_such_handle, test::small_temperature_service_with_response<> )\n{\n    BOOST_CHECK( check_error_response( { 0x0A, 0x17, 0xAA }, 0x0A, 0xAA17, 0x01 ) );\n    BOOST_CHECK( check_error_response( { 0x0A, 0x04, 0x00 }, 0x0A, 0x0004, 0x01 ) );\n}\n\nBOOST_FIXTURE_TEST_CASE( invalid_handle, test::small_temperature_service_with_response<> )\n{\n    BOOST_CHECK( check_error_response( { 0x0A, 0x00, 0x00 }, 0x0A, 0x0000, 0x01 ) );\n}\n\ntypedef bluetoe::server<\n    bluetoe::service<\n        bluetoe::service_uuid< 0x8C8B4094, 0x0DE2, 0x499F, 0xA28A, 0x4EED5BC73CA9 >,\n        bluetoe::characteristic<\n            bluetoe::characteristic_uuid< 0x8C8B4094, 0x0DE2, 0x499F, 0xA28A, 0x4EED5BC73CAA >,\n            bluetoe::bind_characteristic_value< decltype( test::temperature_value ), &test::temperature_value >,\n            bluetoe::no_read_access\n        >\n    >\n> unreadable_server;\n\n\nBOOST_FIXTURE_TEST_CASE( not_readable, test::request_with_reponse< unreadable_server > )\n{\n    BOOST_CHECK( check_error_response( { 0x0A, 0x03, 0x00 }, 0x0A, 0x0003, 0x02 ) );\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE( read_requests )\n\nBOOST_FIXTURE_TEST_CASE( do_i_have_to_wear_a_jacket_today, test::small_temperature_service_with_response<> )\n{\n    l2cap_input( { 0x0A, 0x03, 0x00 } );\n\n    static const std::uint8_t expected_result[] = { 0x0B, 0x04, 0x01 };\n\n    BOOST_CHECK_EQUAL_COLLECTIONS( &response[ 0 ], &response[ response_size ], std::begin( expected_result ), std::end( expected_result ) );\n}\n\nstatic std::uint8_t blob[ 100 ] = { 0 };\n\ntypedef bluetoe::server<\n    bluetoe::service<\n        bluetoe::service_uuid< 0x8C8B4094, 0x0DE2, 0x499F, 0xA28A, 0x4EED5BC73CA9 >,\n        bluetoe::characteristic<\n            bluetoe::characteristic_uuid< 0x8C8B4094, 0x0DE2, 0x499F, 0xA28A, 0x4EED5BC73CAA >,\n            bluetoe::bind_characteristic_value< decltype( blob ), &blob >\n        >\n    >\n> blob_server;\n\nBOOST_FIXTURE_TEST_CASE( read_first_part_of_blob, test::request_with_reponse< blob_server > )\n{\n    l2cap_input( { 0x0A, 0x03, 0x00 } );\n\n    static const std::uint8_t expected_result[] = {\n        0x0B,\n        0x00, 0x00, 0x00, 0x00, 0x00,\n        0x00, 0x00, 0x00, 0x00, 0x00,\n        0x00, 0x00, 0x00, 0x00, 0x00,\n        0x00, 0x00, 0x00, 0x00, 0x00,\n        0x00, 0x00 };\n\n    BOOST_CHECK_EQUAL_COLLECTIONS( &response[ 0 ], &response[ response_size ], std::begin( expected_result ), std::end( expected_result ) );\n}\n\nstatic const char char_name_foo[] = \"Foo\";\nstatic const char char_name_bar[] = \"Bar\";\nstatic const std::uint8_t descriptor_data[] = { 0x08, 0x15 };\n\nusing server_with_fixed_handles = bluetoe::server<\n    bluetoe::no_gap_service_for_gatt_servers,\n    bluetoe::service<\n        bluetoe::attribute_handle< 0x020 >,\n        bluetoe::service_uuid16< 0x0815 >,\n\n        // Characteristic with CCCD and Characteristic User Description without fixed CCCD\n        bluetoe::characteristic<\n            bluetoe::characteristic_uuid16< 0x1516 >,\n            bluetoe::attribute_handles< 0x50, 0x52 >,\n            bluetoe::fixed_uint8_value< 0x42 >,\n            bluetoe::characteristic_name< char_name_foo >,\n            bluetoe::notify\n        >,\n        // Characteristic with CCCD and Characteristic User Description and user descriptor with fixed CCCD\n        bluetoe::characteristic<\n            bluetoe::characteristic_uuid16< 0x1517 >,\n            bluetoe::attribute_handles< 0x60, 0x62, 0x64 >,\n            bluetoe::fixed_uint8_value< 0x43 >,\n            bluetoe::characteristic_name< char_name_bar >,\n            bluetoe::descriptor< 0x1722, descriptor_data, sizeof( descriptor_data ) >,\n            bluetoe::notify\n        >\n    >\n>;\n\nBOOST_FIXTURE_TEST_CASE( read_characteristic_values, test::request_with_reponse< server_with_fixed_handles > )\n{\n    l2cap_input( { 0x0A, 0x52, 0x00 } );\n    expected_result( { 0X0B, 0x42 } );\n\n    l2cap_input( { 0x0A, 0x62, 0x00 } );\n    expected_result( { 0X0B, 0x43 } );\n}\n\nBOOST_FIXTURE_TEST_CASE( read_characteristic_declarations, test::request_with_reponse< server_with_fixed_handles > )\n{\n    l2cap_input( { 0x0A, 0x50, 0x00 } );\n    expected_result( { 0X0B, 0x12, 0x52, 0x00, 0x16, 0x15 } );\n\n    l2cap_input( { 0x0A, 0x60, 0x00 } );\n    expected_result( { 0X0B, 0x12, 0x62, 0x00, 0x17, 0x15 } );\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "tests/att/request_not_supported_tests.cpp",
    "content": "#define BOOST_TEST_MODULE\n#include <boost/test/included/unit_test.hpp>\n\n#include \"test_servers.hpp\"\n\nBOOST_FIXTURE_TEST_CASE( make_sure_unsupported_requests_are_answered_correct, test::small_temperature_service_with_response<> )\n{\n    BOOST_CHECK( check_error_response( { 0x65 }, 0x65, 0x0000, 0x06 ) );\n}\n\nBOOST_FIXTURE_TEST_CASE( make_sure_error_response_is_not_responsed_with_an_error_response, test::small_temperature_service_with_response<> )\n{\n    l2cap_input( { 0x01, 0x01, 0x00, 0x00, 0x06 } );\n    expected_result( {} );\n}\n"
  },
  {
    "path": "tests/att/write_command_tests.cpp",
    "content": "#define BOOST_TEST_MODULE\n#include <boost/test/included/unit_test.hpp>\n\n#include \"test_servers.hpp\"\n\nBOOST_AUTO_TEST_SUITE( write_errors )\n\nBOOST_FIXTURE_TEST_CASE( pdu_to_small, test::small_temperature_service_with_response<> )\n{\n    l2cap_input( { 0x52, 0x02 } );\n    expected_result( {} );\n}\n\nBOOST_FIXTURE_TEST_CASE( no_such_handle, test::small_temperature_service_with_response<> )\n{\n    l2cap_input( { 0x52, 0x17, 0xAA, 0x01 } );\n    expected_result( {} );\n}\n\nBOOST_FIXTURE_TEST_CASE( invalid_handle, test::small_temperature_service_with_response<> )\n{\n    l2cap_input( { 0x52, 0x00, 0x00 } );\n    expected_result( {} );\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE( write_command )\n\nstd::uint32_t value = 0x0000;\n\ntypedef bluetoe::server<\n    bluetoe::service<\n        bluetoe::service_uuid< 0x8C8B4094, 0x0DE2, 0x499F, 0xA28A, 0x4EED5BC73CA9 >,\n        bluetoe::characteristic<\n            bluetoe::characteristic_uuid< 0x8C8B4094, 0x0DE2, 0x499F, 0xA28A, 0x4EED5BC73CAA >,\n            bluetoe::bind_characteristic_value< decltype( value ), &value >\n        >\n    >\n> small_value_server;\n\nBOOST_FIXTURE_TEST_CASE( write_full_data, test::request_with_reponse< small_value_server > )\n{\n    value = 0x3512;\n    l2cap_input( { 0x52, 0x03, 0x00, 0x01, 0x02, 0x03, 0x04 } );\n    expected_result( {} );\n    BOOST_CHECK_EQUAL( value, 0x04030201u );\n}\n\nBOOST_FIXTURE_TEST_CASE( write_full_data_part, test::request_with_reponse< small_value_server > )\n{\n    value = 0x44332211;\n    l2cap_input( { 0x52, 0x03, 0x00, 0x01, 0x02, 0x03 } );\n    expected_result( {} );\n    BOOST_CHECK_EQUAL( value, 0x44030201u );\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "tests/att/write_tests.cpp",
    "content": "#define BOOST_TEST_MODULE\n#include <boost/test/included/unit_test.hpp>\n\n#include \"test_servers.hpp\"\n\nBOOST_AUTO_TEST_SUITE( write_errors )\n\nBOOST_FIXTURE_TEST_CASE( pdu_to_small, test::small_temperature_service_with_response<> )\n{\n    BOOST_CHECK( check_error_response( { 0x12, 0x02 }, 0x12, 0x0000, 0x04 ) );\n}\n\nBOOST_FIXTURE_TEST_CASE( no_such_handle, test::small_temperature_service_with_response<> )\n{\n    BOOST_CHECK( check_error_response( { 0x12, 0x17, 0xAA, 0x01 }, 0x12, 0xAA17, 0x01 ) );\n    BOOST_CHECK( check_error_response( { 0x12, 0x04, 0x00       }, 0x12, 0x0004, 0x01 ) );\n}\n\nBOOST_FIXTURE_TEST_CASE( invalid_handle, test::small_temperature_service_with_response<> )\n{\n    BOOST_CHECK( check_error_response( { 0x12, 0x00, 0x00 }, 0x12, 0x0000, 0x01 ) );\n}\n\nBOOST_FIXTURE_TEST_CASE( write_protected, test::small_temperature_service_with_response<> )\n{\n    BOOST_CHECK( check_error_response( { 0x12, 0x03, 0x00, 0x00, 0x00 }, 0x12, 0x0003, 0x03 ) );\n}\n\nstd::uint32_t value = 0x0000;\n\ntypedef bluetoe::server<\n    bluetoe::service<\n        bluetoe::service_uuid< 0x8C8B4094, 0x0DE2, 0x499F, 0xA28A, 0x4EED5BC73CA9 >,\n        bluetoe::characteristic<\n            bluetoe::characteristic_uuid< 0x8C8B4094, 0x0DE2, 0x499F, 0xA28A, 0x4EED5BC73CAA >,\n            bluetoe::bind_characteristic_value< decltype( value ), &value >\n        >\n    >\n> small_value_server;\n\nBOOST_FIXTURE_TEST_CASE( pdu_to_large, test::request_with_reponse< small_value_server > )\n{\n    value = 0x3512;\n    BOOST_CHECK( check_error_response( { 0x12, 0x03, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05 }, 0x12, 0x0003, 0x0D ) );\n    BOOST_CHECK_EQUAL( value, 0x3512u );\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE( write_requests )\n\nstd::uint32_t value = 0x0000;\n\ntypedef bluetoe::server<\n    bluetoe::service<\n        bluetoe::service_uuid< 0x8C8B4094, 0x0DE2, 0x499F, 0xA28A, 0x4EED5BC73CA9 >,\n        bluetoe::characteristic<\n            bluetoe::characteristic_uuid< 0x8C8B4094, 0x0DE2, 0x499F, 0xA28A, 0x4EED5BC73CAA >,\n            bluetoe::bind_characteristic_value< decltype( value ), &value >\n        >\n    >\n> small_value_server;\n\nBOOST_FIXTURE_TEST_CASE( write_full_data, test::request_with_reponse< small_value_server > )\n{\n    value = 0x3512;\n    l2cap_input( { 0x12, 0x03, 0x00, 0x01, 0x02, 0x03, 0x04 } );\n    expected_result( { 0x13 } );\n    BOOST_CHECK_EQUAL( value, 0x04030201u );\n}\n\nBOOST_FIXTURE_TEST_CASE( write_full_data_part, test::request_with_reponse< small_value_server > )\n{\n    value = 0x44332211;\n    l2cap_input( { 0x12, 0x03, 0x00, 0x01, 0x02, 0x03 } );\n    expected_result( { 0x13 } );\n    BOOST_CHECK_EQUAL( value, 0x44030201u );\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE( write_requests_with_fixed_handles )\n\nstd::uint32_t value = 0x0000;\n\ntypedef bluetoe::server<\n    bluetoe::service<\n        bluetoe::attribute_handle< 0x4444 >,\n        bluetoe::service_uuid< 0x8C8B4094, 0x0DE2, 0x499F, 0xA28A, 0x4EED5BC73CA9 >,\n        bluetoe::characteristic<\n            bluetoe::characteristic_uuid< 0x8C8B4094, 0x0DE2, 0x499F, 0xA28A, 0x4EED5BC73CAA >,\n            bluetoe::bind_characteristic_value< decltype( value ), &value >\n        >\n    >\n> small_value_server;\n\nBOOST_FIXTURE_TEST_CASE( write_full_data, test::request_with_reponse< small_value_server > )\n{\n    value = 0x3512;\n    l2cap_input( { 0x12, 0x46, 0x44, 0x01, 0x02, 0x03, 0x04 } );\n    expected_result( { 0x13 } );\n    BOOST_CHECK_EQUAL( value, 0x04030201u );\n}\n\nBOOST_FIXTURE_TEST_CASE( write_full_data_part, test::request_with_reponse< small_value_server > )\n{\n    value = 0x44332211;\n    l2cap_input( { 0x12, 0x46, 0x44, 0x01, 0x02, 0x03 } );\n    expected_result( { 0x13 } );\n    BOOST_CHECK_EQUAL( value, 0x44030201u );\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "tests/attribute_handle_tests.cpp",
    "content": "#include <bluetoe/attribute_handle.hpp>\n#include <bluetoe/server.hpp>\n\n#define BOOST_TEST_MODULE\n#include <boost/test/included/unit_test.hpp>\n\n#include <bluetoe/server.hpp>\n#include <bluetoe/service.hpp>\n#include <bluetoe/characteristic.hpp>\n\n#include \"test_servers.hpp\"\n#include \"test_attribute_access.hpp\"\n#include \"attribute_io.hpp\"\n\ntemplate < typename Server >\nstruct fixture\n{\n    std::uint16_t handle_by_index( std::size_t index )\n    {\n        return bluetoe::details::handle_index_mapping< Server >::handle_by_index( index );\n    }\n\n    std::size_t index_by_handle( std::uint16_t handle )\n    {\n        return bluetoe::details::handle_index_mapping< Server >::index_by_handle( handle );\n    }\n\n    static std::size_t first_index_by_handle( std::uint16_t handle )\n    {\n        return bluetoe::details::handle_index_mapping< Server >::first_index_by_handle( handle );\n    }\n\n    void check_attribute( std::size_t index, std::initializer_list< std::uint8_t > value )\n    {\n        std::uint8_t value_buffer[ 100 ];\n        std::uint8_t cccd_data[ 10 ] = { 0 };\n        bluetoe::details::client_characteristic_configuration config( cccd_data, sizeof( cccd_data ) );\n        Server srv;\n        auto access = bluetoe::details::attribute_access_arguments::read( value_buffer, 0, config );\n\n        const auto result = srv.attribute_at( index ).access( access, index );\n        BOOST_CHECK_EQUAL( result, bluetoe::details::attribute_access_result::success );\n\n        BOOST_CHECK_EQUAL_COLLECTIONS(\n            value.begin(), value.end(),\n            &value_buffer[ 0 ], &value_buffer[ access.buffer_size ] );\n    }\n};\n\nusing server_with_single_fixed_service = bluetoe::server<\n    bluetoe::no_gap_service_for_gatt_servers,\n    bluetoe::service<\n        bluetoe::attribute_handle< 0x0100 >,\n        bluetoe::service_uuid16< 0x0815 >,\n        bluetoe::characteristic<\n            bluetoe::characteristic_uuid16< 0x0816 >,\n            bluetoe::fixed_uint8_value< 0x42 >\n        >\n    >\n>;\n\n\nBOOST_FIXTURE_TEST_SUITE( mapping_single_fixed_service, fixture< server_with_single_fixed_service > )\n\n    BOOST_AUTO_TEST_CASE( service_handle )\n    {\n        BOOST_CHECK_EQUAL( handle_by_index( 0 ), 0x0100u );\n        BOOST_CHECK_EQUAL( handle_by_index( 1 ), 0x0101u );\n        BOOST_CHECK_EQUAL( handle_by_index( 2 ), 0x0102u );\n        BOOST_CHECK_EQUAL( handle_by_index( 3 ), bluetoe::details::invalid_attribute_handle );\n    }\n\n    BOOST_AUTO_TEST_CASE( attribute_values )\n    {\n        check_attribute( 0, {\n            0x15, 0x08              // 0x0815 service UUID\n        } );\n        check_attribute( 1, {\n            0x02,                   // Properties: Read\n            0x02, 0x01,             // Characteristic Value Attribute Handle: 0x0102\n            0x16, 0x08              // Characteristic UUID\n        } );\n    }\n\n    BOOST_AUTO_TEST_CASE( handle_to_first_index )\n    {\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x010 ), 0u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x100 ), 0u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x101 ), 1u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x102 ), 2u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x103 ), bluetoe::details::invalid_attribute_index );\n    }\n\n    BOOST_AUTO_TEST_CASE( handle_to_index )\n    {\n        BOOST_CHECK_EQUAL( index_by_handle( 0x010 ), bluetoe::details::invalid_attribute_index );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x100 ), 0u );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x101 ), 1u );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x102 ), 2u );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x103 ), bluetoe::details::invalid_attribute_index );\n    }\n\n    BOOST_AUTO_TEST_CASE( invalid_handles )\n    {\n        BOOST_CHECK_EQUAL( index_by_handle( 1 ), bluetoe::details::invalid_attribute_index );\n    }\n\nBOOST_AUTO_TEST_SUITE_END()\n\nusing server_with_single_not_fixed_service = bluetoe::server<\n    bluetoe::no_gap_service_for_gatt_servers,\n    bluetoe::service<\n        bluetoe::service_uuid16< 0x0815 >,\n        bluetoe::characteristic<\n            bluetoe::characteristic_uuid16< 0x0816 >,\n            bluetoe::fixed_uint8_value< 0x42 >\n        >\n    >\n>;\n\nBOOST_FIXTURE_TEST_SUITE( mapping_single_service, fixture< server_with_single_not_fixed_service > )\n\n    BOOST_AUTO_TEST_CASE( service_handle )\n    {\n        BOOST_CHECK_EQUAL( handle_by_index( 0 ), 1u );\n    }\n\n    BOOST_AUTO_TEST_CASE( attribute_values )\n    {\n        check_attribute( 0, {\n            0x15, 0x08              // 0x0815 service UUID\n        } );\n        check_attribute( 1, {\n            0x02,                   // Properties: Read\n            0x03, 0x00,             // Characteristic Value Attribute Handle: 0x0003\n            0x16, 0x08              // Characteristic UUID\n        } );\n    }\n\n    BOOST_AUTO_TEST_CASE( handle_to_first_index )\n    {\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x00 ), 0u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x01 ), 0u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x02 ), 1u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x03 ), 2u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x04 ), bluetoe::details::invalid_attribute_index );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x05 ), bluetoe::details::invalid_attribute_index );\n    }\n\n    BOOST_AUTO_TEST_CASE( handle_to_index )\n    {\n        BOOST_CHECK_EQUAL( index_by_handle( 0x00 ), bluetoe::details::invalid_attribute_index );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x01 ), 0u );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x02 ), 1u );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x03 ), 2u );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x04 ), bluetoe::details::invalid_attribute_index );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x05 ), bluetoe::details::invalid_attribute_index );\n    }\n\nBOOST_AUTO_TEST_SUITE_END()\n\nusing server_with_gap_service_service = bluetoe::server<\n    bluetoe::service<\n        bluetoe::service_uuid16< 0x0815 >,\n        bluetoe::characteristic<\n            bluetoe::fixed_uint8_value< 0x42 >\n        >\n    >\n>;\n\nBOOST_FIXTURE_TEST_SUITE( mapping_single_service_with_gap, fixture< server_with_gap_service_service > )\n\n    BOOST_AUTO_TEST_CASE( all_handles )\n    {\n        // service with single characteristic == 3 handles\n        // GAP Service contains 2 characteristics  == 5 handles\n        BOOST_CHECK_EQUAL( handle_by_index( 0 ), 1u );\n        BOOST_CHECK_EQUAL( handle_by_index( 1 ), 2u );\n        BOOST_CHECK_EQUAL( handle_by_index( 2 ), 3u );\n        BOOST_CHECK_EQUAL( handle_by_index( 3 ), 4u );\n        BOOST_CHECK_EQUAL( handle_by_index( 4 ), 5u );\n        BOOST_CHECK_EQUAL( handle_by_index( 5 ), 6u );\n        BOOST_CHECK_EQUAL( handle_by_index( 6 ), 7u );\n        BOOST_CHECK_EQUAL( handle_by_index( 7 ), 8u );\n        BOOST_CHECK_EQUAL( handle_by_index( 8 ), bluetoe::details::invalid_attribute_handle );\n    }\n\n    BOOST_AUTO_TEST_CASE( handle_to_first_index )\n    {\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x00 ), 0u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x01 ), 0u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x02 ), 1u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x03 ), 2u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x04 ), 3u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x05 ), 4u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x06 ), 5u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x07 ), 6u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x08 ), 7u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x09 ), bluetoe::details::invalid_attribute_index );\n    }\n\n    BOOST_AUTO_TEST_CASE( handle_to_index )\n    {\n        BOOST_CHECK_EQUAL( index_by_handle( 0x00 ), bluetoe::details::invalid_attribute_index );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x01 ), 0u );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x02 ), 1u );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x03 ), 2u );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x04 ), 3u );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x05 ), 4u );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x06 ), 5u );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x07 ), 6u );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x08 ), 7u );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x09 ), bluetoe::details::invalid_attribute_index );\n    }\n\nBOOST_AUTO_TEST_SUITE_END()\n\nusing server_with_gap_and_one_fixed_service = bluetoe::server<\n    bluetoe::service<\n        bluetoe::attribute_handle< 0x010 >,\n        bluetoe::service_uuid16< 0x0815 >,\n        bluetoe::characteristic<\n            bluetoe::fixed_uint8_value< 0x42 >\n        >\n    >\n>;\n\nBOOST_FIXTURE_TEST_SUITE( mapping_with_gap_and_one_fixed_service, bluetoe::details::handle_index_mapping< server_with_gap_and_one_fixed_service > )\n\n    BOOST_AUTO_TEST_CASE( all_handles )\n    {\n        // service with single characteristic == 3 handles\n        // GAP Service contains 2 characteristics  == 5 handles\n        BOOST_CHECK_EQUAL( handle_by_index( 0 ), 0x010u );\n        BOOST_CHECK_EQUAL( handle_by_index( 1 ), 0x011u );\n        BOOST_CHECK_EQUAL( handle_by_index( 2 ), 0x012u );\n        BOOST_CHECK_EQUAL( handle_by_index( 3 ), 0x013u );\n        BOOST_CHECK_EQUAL( handle_by_index( 4 ), 0x014u );\n        BOOST_CHECK_EQUAL( handle_by_index( 5 ), 0x015u );\n        BOOST_CHECK_EQUAL( handle_by_index( 6 ), 0x016u );\n        BOOST_CHECK_EQUAL( handle_by_index( 7 ), 0x017u );\n        BOOST_CHECK_EQUAL( handle_by_index( 8 ), bluetoe::details::invalid_attribute_handle );\n    }\n\n    BOOST_AUTO_TEST_CASE( handle_to_first_index )\n    {\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x0F ), 0u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x10 ), 0u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x11 ), 1u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x12 ), 2u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x13 ), 3u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x14 ), 4u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x15 ), 5u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x16 ), 6u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x17 ), 7u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x18 ), bluetoe::details::invalid_attribute_index );\n    }\n\n    BOOST_AUTO_TEST_CASE( handle_to_index )\n    {\n        BOOST_CHECK_EQUAL( index_by_handle( 0x0F ), bluetoe::details::invalid_attribute_index );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x10 ), 0u );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x11 ), 1u );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x12 ), 2u );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x13 ), 3u );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x14 ), 4u );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x15 ), 5u );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x16 ), 6u );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x17 ), 7u );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x18 ), bluetoe::details::invalid_attribute_index );\n    }\n\nBOOST_AUTO_TEST_SUITE_END()\n\nusing server_with_partial_fixed_services = bluetoe::server<\n    bluetoe::service<\n        bluetoe::service_uuid16< 0x0816 >,\n        bluetoe::characteristic<\n            bluetoe::fixed_uint8_value< 0x42 >\n        >\n    >,\n    bluetoe::service<\n        bluetoe::attribute_handle< 0x010 >,\n        bluetoe::service_uuid16< 0x0815 >,\n        bluetoe::characteristic<\n            bluetoe::fixed_uint8_value< 0x42 >\n        >\n    >\n>;\n\nBOOST_FIXTURE_TEST_SUITE( mapping_with_partial_fixed_services, bluetoe::details::handle_index_mapping< server_with_partial_fixed_services > )\n\n    BOOST_AUTO_TEST_CASE( all_handles )\n    {\n        // 2 service with single characteristic == 6 handles\n        // GAP Service contains 2 characteristics  == 5 handles\n        BOOST_CHECK_EQUAL( handle_by_index( 0 ), 0x001u );\n        BOOST_CHECK_EQUAL( handle_by_index( 1 ), 0x002u );\n        BOOST_CHECK_EQUAL( handle_by_index( 2 ), 0x003u );\n        BOOST_CHECK_EQUAL( handle_by_index( 3 ), 0x010u );\n        BOOST_CHECK_EQUAL( handle_by_index( 4 ), 0x011u );\n        BOOST_CHECK_EQUAL( handle_by_index( 5 ), 0x012u );\n        BOOST_CHECK_EQUAL( handle_by_index( 6 ), 0x013u );\n        BOOST_CHECK_EQUAL( handle_by_index( 7 ), 0x014u );\n        BOOST_CHECK_EQUAL( handle_by_index( 8 ), 0x015u );\n        BOOST_CHECK_EQUAL( handle_by_index( 9 ), 0x016u );\n        BOOST_CHECK_EQUAL( handle_by_index( 10 ), 0x017u );\n        BOOST_CHECK_EQUAL( handle_by_index( 11 ), bluetoe::details::invalid_attribute_handle );\n    }\n\n    BOOST_AUTO_TEST_CASE( handle_to_first_index )\n    {\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x000 ), 0u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x001 ), 0u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x002 ), 1u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x003 ), 2u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x004 ), 3u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x010 ), 3u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x011 ), 4u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x012 ), 5u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x013 ), 6u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x014 ), 7u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x015 ), 8u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x016 ), 9u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x017 ), 10u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x018 ), bluetoe::details::invalid_attribute_index );\n    }\n\n    BOOST_AUTO_TEST_CASE( handle_to_index )\n    {\n        BOOST_CHECK_EQUAL( index_by_handle( 0x000 ), bluetoe::details::invalid_attribute_index );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x001 ), 0u );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x002 ), 1u );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x003 ), 2u );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x004 ), bluetoe::details::invalid_attribute_index );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x010 ), 3u );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x011 ), 4u );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x012 ), 5u );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x013 ), 6u );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x014 ), 7u );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x015 ), 8u );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x016 ), 9u );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x017 ), 10u );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x018 ), bluetoe::details::invalid_attribute_index );\n    }\n\nBOOST_AUTO_TEST_SUITE_END()\n\nusing server_with_multiple_fixed_services = bluetoe::server<\n    bluetoe::service<\n        bluetoe::attribute_handle< 0x020 >,\n        bluetoe::service_uuid16< 0x0816 >,\n        bluetoe::characteristic<\n            bluetoe::fixed_uint8_value< 0x42 >\n        >\n    >,\n    bluetoe::service<\n        bluetoe::attribute_handle< 0x100 >,\n        bluetoe::service_uuid16< 0x0815 >,\n        bluetoe::characteristic<\n            bluetoe::fixed_uint8_value< 0x42 >\n        >\n    >\n>;\n\nBOOST_FIXTURE_TEST_SUITE( mapping_with_multiple_fixed_services, bluetoe::details::handle_index_mapping< server_with_multiple_fixed_services > )\n\n    BOOST_AUTO_TEST_CASE( all_handles )\n    {\n        // 2 service with single characteristic == 6 handles\n        // GAP Service contains 2 characteristics  == 5 handles\n        BOOST_CHECK_EQUAL( handle_by_index( 0 ), 0x020u );\n        BOOST_CHECK_EQUAL( handle_by_index( 1 ), 0x021u );\n        BOOST_CHECK_EQUAL( handle_by_index( 2 ), 0x022u );\n        BOOST_CHECK_EQUAL( handle_by_index( 3 ), 0x100u );\n        BOOST_CHECK_EQUAL( handle_by_index( 4 ), 0x101u );\n        BOOST_CHECK_EQUAL( handle_by_index( 5 ), 0x102u );\n        BOOST_CHECK_EQUAL( handle_by_index( 6 ), 0x103u );\n        BOOST_CHECK_EQUAL( handle_by_index( 7 ), 0x104u );\n        BOOST_CHECK_EQUAL( handle_by_index( 8 ), 0x105u );\n        BOOST_CHECK_EQUAL( handle_by_index( 9 ), 0x106u );\n        BOOST_CHECK_EQUAL( handle_by_index( 10 ), 0x107u );\n        BOOST_CHECK_EQUAL( handle_by_index( 11 ), bluetoe::details::invalid_attribute_handle );\n    }\n\n    BOOST_AUTO_TEST_CASE( handle_to_first_index )\n    {\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x000 ), 0u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x020 ), 0u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x021 ), 1u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x022 ), 2u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x023 ), 3u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x100 ), 3u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x101 ), 4u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x102 ), 5u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x103 ), 6u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x104 ), 7u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x105 ), 8u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x106 ), 9u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x107 ), 10u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x108 ), bluetoe::details::invalid_attribute_index );\n    }\n\n    BOOST_AUTO_TEST_CASE( handle_to_index )\n    {\n        BOOST_CHECK_EQUAL( index_by_handle( 0x000 ), bluetoe::details::invalid_attribute_index );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x020 ), 0u );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x021 ), 1u );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x022 ), 2u );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x023 ), bluetoe::details::invalid_attribute_index );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x100 ), 3u );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x101 ), 4u );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x102 ), 5u );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x103 ), 6u );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x104 ), 7u );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x105 ), 8u );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x106 ), 9u );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x107 ), 10u );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x108 ), bluetoe::details::invalid_attribute_index );\n    }\n\nBOOST_AUTO_TEST_SUITE_END()\n\nusing server_with_multiple_fixed_services_and_characteristics = bluetoe::server<\n    bluetoe::service<\n        bluetoe::attribute_handle< 0x020 >,\n        bluetoe::service_uuid16< 0x0816 >,\n        bluetoe::characteristic<\n            bluetoe::fixed_uint8_value< 0x42 >\n        >,\n        bluetoe::characteristic<\n            bluetoe::attribute_handle< 0x100 >,\n            bluetoe::fixed_uint8_value< 0x42 >,\n            bluetoe::notify\n        >\n    >,\n    bluetoe::service<\n        bluetoe::service_uuid16< 0x0815 >,\n        bluetoe::characteristic<\n            bluetoe::attribute_handle< 0x200 >,\n            bluetoe::fixed_uint8_value< 0x42 >,\n            bluetoe::notify\n        >,\n        bluetoe::characteristic<\n            bluetoe::fixed_uint8_value< 0x42 >\n        >\n    >\n>;\n\nBOOST_FIXTURE_TEST_SUITE( mapping_with_multiple_fixed_services_and_characteristics, bluetoe::details::handle_index_mapping< server_with_multiple_fixed_services_and_characteristics > )\n\n    BOOST_AUTO_TEST_CASE( all_handles )\n    {\n        // first service\n        BOOST_CHECK_EQUAL( handle_by_index( 0 ), 0x020u );\n            // 2 Characteristics\n            BOOST_CHECK_EQUAL( handle_by_index( 1 ), 0x021u );\n            BOOST_CHECK_EQUAL( handle_by_index( 2 ), 0x022u );\n\n            BOOST_CHECK_EQUAL( handle_by_index( 3 ), 0x100u );\n            BOOST_CHECK_EQUAL( handle_by_index( 4 ), 0x101u );\n            BOOST_CHECK_EQUAL( handle_by_index( 5 ), 0x102u );\n\n        // second service\n        BOOST_CHECK_EQUAL( handle_by_index( 6 ), 0x103u );\n            // 2 Characteristics\n            BOOST_CHECK_EQUAL( handle_by_index( 7 ), 0x200u );\n            BOOST_CHECK_EQUAL( handle_by_index( 8 ), 0x201u );\n            BOOST_CHECK_EQUAL( handle_by_index( 9 ), 0x202u );\n\n            BOOST_CHECK_EQUAL( handle_by_index( 10 ), 0x203u );\n            BOOST_CHECK_EQUAL( handle_by_index( 11 ), 0x204u );\n\n        // GAP Service\n        BOOST_CHECK_EQUAL( handle_by_index( 12 ), 0x205u );\n            // 2 Characteristics\n            BOOST_CHECK_EQUAL( handle_by_index( 13 ), 0x206u );\n            BOOST_CHECK_EQUAL( handle_by_index( 14 ), 0x207u );\n\n            BOOST_CHECK_EQUAL( handle_by_index( 15 ), 0x208u );\n            BOOST_CHECK_EQUAL( handle_by_index( 16 ), 0x209u );\n\n        BOOST_CHECK_EQUAL( handle_by_index( 17 ), bluetoe::details::invalid_attribute_handle );\n    }\n\n    BOOST_AUTO_TEST_CASE( handle_to_first_index )\n    {\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x01f ), 0u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x020 ), 0u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x021 ), 1u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x022 ), 2u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x023 ), 3u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x100 ), 3u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x101 ), 4u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x102 ), 5u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x103 ), 6u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x104 ), 7u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x200 ), 7u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x201 ), 8u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x202 ), 9u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x203 ), 10u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x204 ), 11u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x205 ), 12u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x206 ), 13u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x207 ), 14u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x208 ), 15u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x209 ), 16u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x20a ), bluetoe::details::invalid_attribute_index );\n    }\n\n    BOOST_AUTO_TEST_CASE( handle_to_index )\n    {\n        BOOST_CHECK_EQUAL( index_by_handle( 0x01f ), bluetoe::details::invalid_attribute_index );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x020 ), 0u );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x021 ), 1u );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x022 ), 2u );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x023 ), bluetoe::details::invalid_attribute_index );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x100 ), 3u );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x101 ), 4u );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x102 ), 5u );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x103 ), 6u );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x104 ), bluetoe::details::invalid_attribute_index );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x200 ), 7u );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x201 ), 8u );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x202 ), 9u );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x203 ), 10u );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x204 ), 11u );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x205 ), 12u );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x206 ), 13u );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x207 ), 14u );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x208 ), 15u );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x209 ), 16u );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x20a ), bluetoe::details::invalid_attribute_index );\n    }\n\nBOOST_AUTO_TEST_SUITE_END()\n\n\nusing server_with_multiple_fixed_attributes_handles = bluetoe::server<\n    bluetoe::no_gap_service_for_gatt_servers,\n    bluetoe::service<\n        bluetoe::attribute_handle< 0x020 >,\n        bluetoe::service_uuid16< 0x0816 >,\n\n        bluetoe::characteristic<\n            bluetoe::characteristic_uuid16< 0x0816 >,\n            bluetoe::attribute_handles< 0x50, 0x52 >,\n            bluetoe::fixed_uint8_value< 0x42 >\n        >,\n        bluetoe::characteristic<\n            bluetoe::characteristic_uuid16< 0x0817 >,\n            bluetoe::attribute_handles< 0x60, 0x62, 0x64 >,\n            bluetoe::fixed_uint8_value< 0x43 >,\n            bluetoe::notify\n        >\n    >,\n    bluetoe::service<\n        bluetoe::service_uuid16< 0x0815 >,\n        bluetoe::characteristic<\n            bluetoe::characteristic_uuid16< 0x0816 >,\n            bluetoe::fixed_uint8_value< 0x44 >,\n            bluetoe::notify\n        >,\n        bluetoe::characteristic<\n            bluetoe::characteristic_uuid16< 0x0818 >,\n            bluetoe::attribute_handles< 0x100, 0x101 >,\n            bluetoe::fixed_uint8_value< 0x45 >\n        >\n    >\n>;\n\nBOOST_FIXTURE_TEST_SUITE( mapping_with_multiple_fixed_attributes_handles, fixture< server_with_multiple_fixed_attributes_handles > )\n\n    BOOST_AUTO_TEST_CASE( all_handles )\n    {\n        // first service\n        BOOST_CHECK_EQUAL( handle_by_index( 0 ), 0x020u );\n            // 2 Characteristics\n            BOOST_CHECK_EQUAL( handle_by_index( 1 ), 0x050u );\n            BOOST_CHECK_EQUAL( handle_by_index( 2 ), 0x052u );\n\n            BOOST_CHECK_EQUAL( handle_by_index( 3 ), 0x060u );\n            BOOST_CHECK_EQUAL( handle_by_index( 4 ), 0x062u );\n            BOOST_CHECK_EQUAL( handle_by_index( 5 ), 0x064u );\n\n        // second service\n        BOOST_CHECK_EQUAL( handle_by_index( 6 ), 0x065u );\n            // 2 Characteristics\n            BOOST_CHECK_EQUAL( handle_by_index( 7 ), 0x066u );\n            BOOST_CHECK_EQUAL( handle_by_index( 8 ), 0x067u );\n            BOOST_CHECK_EQUAL( handle_by_index( 9 ), 0x068u );\n\n            BOOST_CHECK_EQUAL( handle_by_index( 10 ), 0x100u );\n            BOOST_CHECK_EQUAL( handle_by_index( 11 ), 0x101u );\n\n        BOOST_CHECK_EQUAL( handle_by_index( 12 ), bluetoe::details::invalid_attribute_handle );\n    }\n\n    BOOST_AUTO_TEST_CASE( handle_to_first_index )\n    {\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x01f ), 0u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x020 ), 0u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x021 ), 1u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x050 ), 1u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x051 ), 2u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x052 ), 2u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x053 ), 3u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x060 ), 3u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x061 ), 4u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x062 ), 4u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x063 ), 5u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x064 ), 5u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x065 ), 6u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x066 ), 7u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x067 ), 8u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x068 ), 9u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x069 ), 10u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x100 ), 10u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x101 ), 11u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x102 ), bluetoe::details::invalid_attribute_index );\n    }\n\n    BOOST_AUTO_TEST_CASE( handle_to_index )\n    {\n        BOOST_CHECK_EQUAL( index_by_handle( 0x01f ), bluetoe::details::invalid_attribute_index );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x020 ), 0u );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x021 ), bluetoe::details::invalid_attribute_index );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x050 ), 1u );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x051 ), bluetoe::details::invalid_attribute_index );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x052 ), 2u );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x053 ), bluetoe::details::invalid_attribute_index );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x060 ), 3u );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x061 ), bluetoe::details::invalid_attribute_index );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x062 ), 4u );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x063 ), bluetoe::details::invalid_attribute_index );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x064 ), 5u );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x065 ), 6u );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x066 ), 7u );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x067 ), 8u );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x068 ), 9u );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x069 ), bluetoe::details::invalid_attribute_index );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x100 ), 10u );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x101 ), 11u );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x102 ), bluetoe::details::invalid_attribute_index );\n    }\n\n    BOOST_AUTO_TEST_CASE( attribute_values )\n    {\n        // first service\n        check_attribute( 0, {\n            0x16, 0x08              // 0x0815 service UUID\n        } );\n\n        // first characteristic\n        check_attribute( 1, {\n            0x02,                   // Properties: Read\n            0x52, 0x00,             // Characteristic Value Attribute Handle: 0x0052\n            0x16, 0x08              // Characteristic UUID\n        } );\n        check_attribute( 2, { 0x42 } ); // Value\n\n        // second characteristic\n        check_attribute( 3, {\n            0x12,                   // Properties: Read, Notify\n            0x62, 0x00,             // Characteristic Value Attribute Handle: 0x0062\n            0x17, 0x08              // Characteristic UUID\n        } );\n        check_attribute( 4, { 0x43 } ); // Value\n        check_attribute( 5, { 0x00, 0x00 } ); // CCCD configuration\n\n        // second service\n        check_attribute( 6, {\n            0x15, 0x08              // 0x0815 service UUID\n        } );\n\n        // first characteristic\n        check_attribute( 7, {\n            0x12,                   // Properties: Read, Notify\n            0x67, 0x00,             // Characteristic Value Attribute Handle: 0x0067\n            0x16, 0x08              // Characteristic UUID\n        } );\n        check_attribute( 8, { 0x44 } ); // Value\n        check_attribute( 9, { 0x00, 0x00 } ); // CCCD configuration\n\n        // second characteristic\n        check_attribute( 10, {\n            0x02,                   // Properties: Read\n            0x01, 0x01,             // Characteristic Value Attribute Handle: 0x0101\n            0x18, 0x08              // Characteristic UUID\n        } );\n        check_attribute( 11, { 0x45 } ); // Value\n    }\n\nBOOST_AUTO_TEST_SUITE_END()\n\nstatic const char char_name_foo[] = \"Foo\";\nstatic const char char_name_bar[] = \"Bar\";\nstatic const char char_name_baz[] = \"Baz\";\nstatic const std::uint8_t descriptor_data[] = { 0x08, 0x15 };\n\nusing server_with_additional_descriptors = bluetoe::server<\n    bluetoe::no_gap_service_for_gatt_servers,\n    bluetoe::service<\n        bluetoe::attribute_handle< 0x020 >,\n        bluetoe::service_uuid16< 0x0815 >,\n\n        // Characteristic with CCCD and Characteristic User Description without fixed CCCD\n        bluetoe::characteristic<\n            bluetoe::characteristic_uuid16< 0x1516 >,\n            bluetoe::attribute_handles< 0x50, 0x52 >,\n            bluetoe::fixed_uint8_value< 0x42 >,\n            bluetoe::characteristic_name< char_name_foo >,\n            bluetoe::notify\n        >,\n        // Characteristic with CCCD and Characteristic User Description and user descriptor with fixed CCCD\n        bluetoe::characteristic<\n            bluetoe::characteristic_uuid16< 0x1517 >,\n            bluetoe::attribute_handles< 0x60, 0x62, 0x64 >,\n            bluetoe::fixed_uint8_value< 0x43 >,\n            bluetoe::characteristic_name< char_name_bar >,\n            bluetoe::descriptor< 0x1722, descriptor_data, sizeof( descriptor_data ) >,\n            bluetoe::notify\n        >,\n        // No descriptors, no fixup\n        bluetoe::characteristic<\n            bluetoe::characteristic_uuid16< 0x1518 >,\n            bluetoe::fixed_uint8_value< 0x44 >\n        >,\n        // Characteristic Characteristic User Description without fixed CCCD\n        bluetoe::characteristic<\n            bluetoe::characteristic_uuid16< 0x1519 >,\n            bluetoe::attribute_handles< 0x70, 0x80 >,\n            bluetoe::fixed_uint8_value< 0x45 >,\n            bluetoe::characteristic_name< char_name_baz >\n        >\n    >\n>;\n\nBOOST_FIXTURE_TEST_SUITE( mapping_server_with_additional_descriptors, fixture< server_with_additional_descriptors > )\n\n    BOOST_AUTO_TEST_CASE( all_handles )\n    {\n        // first service\n        BOOST_CHECK_EQUAL( handle_by_index( 0 ), 0x020u );\n            // Declaration, Value, CCCD, User Description\n            BOOST_CHECK_EQUAL( handle_by_index( 1 ), 0x050u );\n            BOOST_CHECK_EQUAL( handle_by_index( 2 ), 0x052u );\n            BOOST_CHECK_EQUAL( handle_by_index( 3 ), 0x053u );\n            BOOST_CHECK_EQUAL( handle_by_index( 4 ), 0x054u );\n\n            // Declaration, Value, CCCD, User Description\n            BOOST_CHECK_EQUAL( handle_by_index( 5 ), 0x060u );\n            BOOST_CHECK_EQUAL( handle_by_index( 6 ), 0x062u );\n            BOOST_CHECK_EQUAL( handle_by_index( 7 ), 0x064u );\n            BOOST_CHECK_EQUAL( handle_by_index( 8 ), 0x065u );\n            BOOST_CHECK_EQUAL( handle_by_index( 9 ), 0x066u );\n\n            // Declaration, Value without fixup\n            BOOST_CHECK_EQUAL( handle_by_index( 10 ), 0x067u );\n            BOOST_CHECK_EQUAL( handle_by_index( 11 ), 0x068u );\n\n            // Declaration, Value, User Description\n            BOOST_CHECK_EQUAL( handle_by_index( 12 ), 0x070u );\n            BOOST_CHECK_EQUAL( handle_by_index( 13 ), 0x080u );\n            BOOST_CHECK_EQUAL( handle_by_index( 14 ), 0x081u );\n\n        BOOST_CHECK_EQUAL( handle_by_index( 15 ), bluetoe::details::invalid_attribute_handle );\n    }\n\n    BOOST_AUTO_TEST_CASE( handle_to_first_index )\n    {\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x01f ), 0u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x020 ), 0u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x021 ), 1u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x050 ), 1u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x051 ), 2u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x052 ), 2u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x053 ), 3u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x054 ), 4u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x055 ), 5u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x060 ), 5u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x061 ), 6u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x062 ), 6u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x063 ), 7u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x064 ), 7u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x065 ), 8u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x066 ), 9u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x067 ), 10u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x068 ), 11u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x069 ), 12u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x070 ), 12u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x071 ), 13u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x07F ), 13u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x080 ), 13u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x081 ), 14u );\n        BOOST_CHECK_EQUAL( first_index_by_handle( 0x082 ), bluetoe::details::invalid_attribute_index );\n    }\n\n    BOOST_AUTO_TEST_CASE( handle_to_index )\n    {\n        BOOST_CHECK_EQUAL( index_by_handle( 0x01f ), bluetoe::details::invalid_attribute_index );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x020 ), 0u );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x021 ), bluetoe::details::invalid_attribute_index );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x050 ), 1u );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x051 ), bluetoe::details::invalid_attribute_index );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x052 ), 2u );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x053 ), 3u );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x054 ), 4u );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x055 ), bluetoe::details::invalid_attribute_index );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x060 ), 5u );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x061 ), bluetoe::details::invalid_attribute_index );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x062 ), 6u );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x063 ), bluetoe::details::invalid_attribute_index );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x064 ), 7u );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x065 ), 8u );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x066 ), 9u );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x067 ), 10u );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x068 ), 11u );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x069 ), bluetoe::details::invalid_attribute_index );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x070 ), 12u );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x071 ), bluetoe::details::invalid_attribute_index );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x07F ), bluetoe::details::invalid_attribute_index );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x080 ), 13u );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x081 ), 14u );\n        BOOST_CHECK_EQUAL( index_by_handle( 0x082 ), bluetoe::details::invalid_attribute_index );\n    }\n\n    /*\n     * This test tests, that the descriptors are in the expected order within the characteristic\n     */\n    BOOST_AUTO_TEST_CASE( attribute_values )\n    {\n        // first service\n        check_attribute( 0, {\n            0x15, 0x08              // 0x0815 service UUID\n        } );\n\n        // first characteristic\n        check_attribute( 1, {\n            0x12,                   // Properties: Read, Notify\n            0x52, 0x00,             // Characteristic Value Attribute Handle: 0x0052\n            0x16, 0x15              // UUID\n        } );\n        check_attribute( 2, {\n            0x42                    // Value\n        } );\n        check_attribute( 3, {\n            0x00, 0x00              // CCCD\n        } );\n        check_attribute( 4, {\n            'F', 'o', 'o'           // Characteristic User Description\n        } );\n\n        // second characteristic\n        check_attribute( 5, {\n            0x12,                   // Properties: Read, Notify\n            0x62, 0x00,             // Characteristic Value Attribute Handle: 0x0062\n            0x17, 0x15              // UUID\n        } );\n        check_attribute( 6, {\n            0x43                    // Value\n        } );\n        check_attribute( 7, {\n            0x00, 0x00              // CCCD\n        } );\n        check_attribute( 8, {\n            'B', 'a', 'r'           // Characteristic User Description\n        } );\n        check_attribute( 9, {\n            0x08, 0x15              // User defined descriptor\n        } );\n\n        // third characteristic\n        check_attribute( 10, {\n            0x02,                   // Properties: Read\n            0x68, 0x00,             // Characteristic Value Attribute Handle: 0x0068\n            0x18, 0x15              // UUID\n        } );\n        check_attribute( 11, {\n            0x44                    // Value\n        } );\n\n        // forth characteristic\n        check_attribute( 12, {\n            0x02,                   // Properties: Read\n            0x80, 0x00,             // Characteristic Value Attribute Handle: 0x0070\n            0x19, 0x15              // UUID\n        } );\n        check_attribute( 13, {\n            0x45                    // Value\n        } );\n        check_attribute( 14, {\n            'B', 'a', 'z'           // Characteristic User Description\n        } );\n   }\n\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "tests/auto_uuid_tests.cpp",
    "content": "#include <iostream>\n#include <array>\n#include <bluetoe/service.hpp>\n\n#define BOOST_TEST_MODULE\n#include <boost/test/included/unit_test.hpp>\n\n#include \"test_attribute_access.hpp\"\n#include \"hexdump.hpp\"\n\nnamespace blued = bluetoe::details;\n\nBOOST_AUTO_TEST_SUITE( implicit_characteristic_uuid )\n\n    static std::int64_t x_pos;\n    static std::int64_t y_pos;\n    static std::int64_t z_pos;\n\n    using auto_uuid_service = bluetoe::service<\n        bluetoe::characteristic<\n            bluetoe::bind_characteristic_value< decltype( x_pos ), &x_pos >\n        >,\n        bluetoe::characteristic<\n            bluetoe::bind_characteristic_value< decltype( y_pos ), &y_pos >\n        >,\n        bluetoe::characteristic<\n            bluetoe::bind_characteristic_value< decltype( z_pos ), &z_pos >\n        >,\n\n        bluetoe::service_uuid< 0xD7E08435, 0xA713, 0x4A51, 0x92DB, 0x004A8C63B6F8 >\n\n        // if this is changed to a 16 bit UUID, it should not compile\n        //bluetoe::service_uuid16< 0x0815 >\n    >;\n\n    BOOST_FIXTURE_TEST_CASE( check_expected_number_of_attributes, auto_uuid_service )\n    {\n        BOOST_CHECK_EQUAL( int( number_of_attributes ), 7 );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( three_different_uuids_in_characteristic_value_declaration, auto_uuid_service )\n    {\n        static const std::array< std::uint8_t, 16u > service_uuid = { {\n            0xf8, 0xb6, 0x63, 0x8c, 0x4a, 0x00, 0xdb, 0x92,\n            0x51, 0x4a, 0x13, 0xa7, 0x35, 0x84, 0xe0, 0xd7\n        } };\n\n        static const std::size_t attribute_indices[] = { 1, 3, 5 };\n\n        for ( int attribute_index = 0; attribute_index != sizeof( attribute_indices ) / sizeof( attribute_indices[ 0 ] ); ++attribute_index )\n        {\n             // the expected UUID is the service uuid, with the lsb xored by the characteristic index\n            auto expected_char_uuid = service_uuid;\n            expected_char_uuid[ 0 ] ^= attribute_index +1;\n\n            std::uint8_t uuid[ 16 ] = { 0 };\n\n            auto read = blued::attribute_access_arguments::read( uuid, 3 );\n            auto attr = attribute_at< std::tuple<>, 0, std::tuple< auto_uuid_service >, bluetoe::server< auto_uuid_service > >( attribute_indices[ attribute_index ] );\n\n            auto result = attr.access( read, attribute_indices[ attribute_index ] );\n            BOOST_CHECK( result == blued::attribute_access_result::success );\n\n            BOOST_CHECK_EQUAL_COLLECTIONS( std::begin( expected_char_uuid ), std::end( expected_char_uuid ), std::begin( uuid ), std::begin( uuid ) + read.buffer_size );\n        }\n    }\n\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "tests/bits_tests.cpp",
    "content": "#define BOOST_TEST_MODULE\n#include <boost/test/included/unit_test.hpp>\n\n#include <bluetoe/bits.hpp>\n\nBOOST_AUTO_TEST_CASE( no_distance )\n{\n    BOOST_TEST( bluetoe::details::distance< std::uint16_t >( 0u, 0u ) == 0 );\n    BOOST_TEST( bluetoe::details::distance< std::uint16_t >( 0xfff2u, 0xfff2u ) == 0 );\n    BOOST_TEST( bluetoe::details::distance< std::uint16_t >( 0x4444u, 0x4444u ) == 0 );\n}\n\nBOOST_AUTO_TEST_CASE( positive_distance )\n{\n    BOOST_TEST( bluetoe::details::distance< std::uint16_t >( 0u, 1u ) == 1 );\n    BOOST_TEST( bluetoe::details::distance< std::uint16_t >( 0x0ff2u, 0x4ff2u ) == 0x4000 );\n    BOOST_TEST( bluetoe::details::distance< std::uint16_t >( 0xf444u, 0x0444u ) == 0x1000 );\n}\n\nBOOST_AUTO_TEST_CASE( negative_distance )\n{\n    BOOST_TEST( bluetoe::details::distance< std::uint16_t >( 1u, 0u ) == -1 );\n    BOOST_TEST( bluetoe::details::distance< std::uint16_t >( 0x4ff2u, 0x0ff2u ) == -0x4000 );\n    BOOST_TEST( bluetoe::details::distance< std::uint16_t >( 0x0444u, 0xf444u ) == -0x1000 );\n}\n\nBOOST_AUTO_TEST_CASE( no_distance_n )\n{\n    BOOST_TEST( ( bluetoe::details::distance_n< 24u, std::uint32_t >( 0xffffff, 0xffffff ) ) == 0 );\n    BOOST_TEST( ( bluetoe::details::distance_n< 24u, std::uint32_t >( 0x0, 0x0 ) ) == 0 );\n    BOOST_TEST( ( bluetoe::details::distance_n< 24u, std::uint32_t >( 0x800000, 0x800000 ) ) == 0 );\n}\n\nBOOST_AUTO_TEST_CASE( positive_distance_n )\n{\n    BOOST_TEST( ( bluetoe::details::distance_n< 24u, std::uint32_t >( 0xffffff, 0x7a ) ) == 0x7b );\n    BOOST_TEST( ( bluetoe::details::distance_n< 24u, std::uint32_t >( 0x0, 0x7fffff ) ) == 0x7fffff );\n}\n\nBOOST_AUTO_TEST_CASE( negative_distance_n )\n{\n    BOOST_TEST( ( bluetoe::details::distance_n< 24u, std::uint32_t >( 0x7a, 0xffffff ) ) == -0x7b );\n    BOOST_TEST( ( bluetoe::details::distance_n< 24u, std::uint32_t >( 0x0, 0x800001 ) ) == -0x7fffff );\n}\n"
  },
  {
    "path": "tests/characteristic_tests.cpp",
    "content": "#include <iostream>\n#include <cstdint>\n\n#include <bluetoe/characteristic.hpp>\n#include <bluetoe/service.hpp>\n#include <bluetoe/client_characteristic_configuration.hpp>\n\n#define BOOST_TEST_MODULE\n#include <boost/test/included/unit_test.hpp>\n#include \"hexdump.hpp\"\n#include \"test_attribute_access.hpp\"\n#include \"test_characteristics.hpp\"\n\nusing cccd_indices = std::tuple<>;\nusing suuid = bluetoe::service_uuid16< 0x4711 >;\nusing srv   = bluetoe::server<>;\n\nBOOST_AUTO_TEST_CASE( even_the_simplest_characteristic_has_at_least_2_attributes )\n{\n    BOOST_CHECK_GE( std::size_t( simple_char::number_of_attributes ), 2u );\n}\n\nBOOST_FIXTURE_TEST_CASE( the_first_attribute_is_the_characteristic_declaration, simple_char )\n{\n    const bluetoe::details::attribute char_declaration = attribute_at< cccd_indices, 0, bluetoe::service< suuid >, srv >( 0 );\n\n    BOOST_CHECK_EQUAL( char_declaration.uuid, 0x2803 );\n}\n\nBOOST_AUTO_TEST_SUITE( characteristic_declaration_access )\n\n    BOOST_FIXTURE_TEST_CASE( the_characteristic_declaration_has_a_length_of_19, simple_char )\n    {\n        const bluetoe::details::attribute char_declaration = attribute_at< cccd_indices, 0, bluetoe::service< suuid >, srv >( 0 );\n        std::uint8_t buffer[ 100 ];\n        auto read = bluetoe::details::attribute_access_arguments::read( buffer, 0 );\n\n        BOOST_REQUIRE( char_declaration.access );\n        char_declaration.access( read, 1 );\n\n        BOOST_CHECK_EQUAL( read.buffer_size, 19u );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( the_characteristic_declaration_has_a_length_of_17_with_offset_2, simple_char )\n    {\n        const bluetoe::details::attribute char_declaration = attribute_at< cccd_indices, 0, bluetoe::service< suuid >, srv >( 0 );\n        std::uint8_t buffer[ 100 ];\n        auto read = bluetoe::details::attribute_access_arguments::read( buffer, 2 );\n\n        BOOST_REQUIRE( char_declaration.access );\n        char_declaration.access( read, 1 );\n\n        BOOST_CHECK_EQUAL( read.buffer_size, 17u );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( the_characteristic_declaration_has_a_length_of_0_with_offset_19, simple_char )\n    {\n        const bluetoe::details::attribute char_declaration = attribute_at< cccd_indices, 0, bluetoe::service< suuid >, srv >( 0 );\n        std::uint8_t buffer[ 100 ];\n        auto read = bluetoe::details::attribute_access_arguments::read( buffer, 19 );\n\n        BOOST_REQUIRE( char_declaration.access );\n        BOOST_CHECK( char_declaration.access( read, 1 ) == bluetoe::details::attribute_access_result::success );\n\n        BOOST_CHECK_EQUAL( read.buffer_size, 0u );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( the_characteristic_declaration_returns_invalid_offset_when_read_behind_data, simple_char )\n    {\n        const bluetoe::details::attribute char_declaration = attribute_at< cccd_indices, 0, bluetoe::service< suuid >, srv >( 0 );\n        std::uint8_t buffer[ 100 ];\n        auto read = bluetoe::details::attribute_access_arguments::read( buffer, 20 );\n\n        BOOST_CHECK( char_declaration.access( read, 1 ) == bluetoe::details::attribute_access_result::invalid_offset );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( the_short_characteristic_declaration_has_a_length_of_5, short_uuid_char )\n    {\n        const bluetoe::details::attribute char_declaration = attribute_at< cccd_indices, 0, bluetoe::service< suuid >, srv >( 0 );\n        std::uint8_t buffer[ 100 ];\n        auto read = bluetoe::details::attribute_access_arguments::read( buffer, 0 );\n\n        char_declaration.access( read, 1 );\n\n        BOOST_CHECK_EQUAL( read.buffer_size, 5u );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( the_short_characteristic_declaration_has_a_length_of_4_with_offset_1, short_uuid_char )\n    {\n        const bluetoe::details::attribute char_declaration = attribute_at< cccd_indices, 0, bluetoe::service< suuid >, srv >( 0 );\n        std::uint8_t buffer[ 100 ];\n        auto read = bluetoe::details::attribute_access_arguments::read( buffer, 1 );\n\n        char_declaration.access( read, 1 );\n\n        BOOST_CHECK_EQUAL( read.buffer_size, 4u );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( the_short_characteristic_declaration_has_a_length_of_1_with_offset_4, short_uuid_char )\n    {\n        const bluetoe::details::attribute char_declaration = attribute_at< cccd_indices, 0, bluetoe::service< suuid >, srv >( 0 );\n        std::uint8_t buffer[ 100 ];\n        auto read = bluetoe::details::attribute_access_arguments::read( buffer, 4 );\n\n        char_declaration.access( read, 1 );\n\n        BOOST_CHECK_EQUAL( read.buffer_size, 1u );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( the_characteristic_declaration_contains_the_uuid, simple_char )\n    {\n        const bluetoe::details::attribute char_declaration = attribute_at< cccd_indices, 0, bluetoe::service< suuid >, srv >( 0 );\n        std::uint8_t buffer[ 100 ];\n        auto read = bluetoe::details::attribute_access_arguments::read( buffer, 0 );\n\n        BOOST_CHECK( bluetoe::details::attribute_access_result::success == char_declaration.access( read, 1 ) );\n\n        // D0B10674-6DDD-4B59-89CA-A009B78C956B\n        static const std::uint8_t expected_uuid[] = { 0x6B, 0x95, 0x8C, 0xB7, 0x09, 0xA0, 0xCA, 0x89, 0x59, 0x4B, 0xDD, 0x6D, 0x74, 0x06, 0xB1, 0xD0 };\n        BOOST_CHECK_EQUAL_COLLECTIONS( std::begin( expected_uuid ), std::end( expected_uuid ), &buffer[ 3 ], &buffer[ 19 ] );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( the_characteristic_declaration_contains_the_uuid_at_offset_3, simple_char )\n    {\n        const bluetoe::details::attribute char_declaration = attribute_at< cccd_indices, 0, bluetoe::service< suuid >, srv >( 0 );\n        std::uint8_t buffer[ 100 ];\n        auto read = bluetoe::details::attribute_access_arguments::read( buffer, 3 );\n\n        BOOST_CHECK( bluetoe::details::attribute_access_result::success == char_declaration.access( read, 1 ) );\n\n        // D0B10674-6DDD-4B59-89CA-A009B78C956B\n        static const std::uint8_t expected_uuid[] = { 0x6B, 0x95, 0x8C, 0xB7, 0x09, 0xA0, 0xCA, 0x89, 0x59, 0x4B, 0xDD, 0x6D, 0x74, 0x06, 0xB1, 0xD0 };\n        BOOST_CHECK_EQUAL_COLLECTIONS( std::begin( expected_uuid ), std::end( expected_uuid ), &buffer[ 0 ], &buffer[ 16 ] );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( the_characteristic_declaration_contains_the_value_handle, simple_char )\n    {\n        const bluetoe::details::attribute char_declaration = attribute_at< cccd_indices, 0, bluetoe::service< suuid >, srv >( 0 );\n        std::uint8_t buffer[ 100 ];\n        auto read = bluetoe::details::attribute_access_arguments::read( buffer, 0 );\n\n        BOOST_CHECK( bluetoe::details::attribute_access_result::success == char_declaration.access( read, 0 ) );\n\n        static const std::uint8_t expected_handle[] = { 0x02, 0x00 };\n        BOOST_CHECK_EQUAL_COLLECTIONS( std::begin( expected_handle ), std::end( expected_handle ), &buffer[ 1 ], &buffer[ 3 ] );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( the_characteristic_declaration_contains_the_value_handle_at_offset_1, simple_char )\n    {\n        const bluetoe::details::attribute char_declaration = attribute_at< cccd_indices, 0, bluetoe::service< suuid >, srv >( 0 );\n        std::uint8_t buffer[ 100 ];\n        auto read = bluetoe::details::attribute_access_arguments::read( buffer, 1 );\n\n        BOOST_CHECK( bluetoe::details::attribute_access_result::success == char_declaration.access( read, 0 ) );\n\n        static const std::uint8_t expected_handle[] = { 0x02, 0x00 };\n        BOOST_CHECK_EQUAL_COLLECTIONS( std::begin( expected_handle ), std::end( expected_handle ), &buffer[ 0 ], &buffer[ 2 ] );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( the_characteristic_declaration_contains_the_hibyte_of_the_value_handle_at_offset_2, simple_char )\n    {\n        const bluetoe::details::attribute char_declaration = attribute_at< cccd_indices, 0, bluetoe::service< suuid >, srv >( 0 );\n        std::uint8_t buffer[ 100 ];\n        auto read = bluetoe::details::attribute_access_arguments::read( buffer, 2 );\n\n        BOOST_CHECK( bluetoe::details::attribute_access_result::success == char_declaration.access( read, 0 ) );\n\n        BOOST_CHECK_EQUAL( buffer[ 0 ], 0x00 );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( read_char_declaration_buffer_to_small, simple_char )\n    {\n        const bluetoe::details::attribute char_declaration = attribute_at< cccd_indices, 0, bluetoe::service< suuid >, srv >( 0 );\n        std::uint8_t buffer[ 17 ];\n        auto read = bluetoe::details::attribute_access_arguments::read( buffer, 0 );\n\n        BOOST_CHECK( bluetoe::details::attribute_access_result::success == char_declaration.access( read, 1 ) );\n        BOOST_CHECK_EQUAL( read.buffer_size, 17u );\n        static const std::uint8_t expected_uuid[] = { 0x6B, 0x95, 0x8C, 0xB7, 0x09, 0xA0, 0xCA, 0x89, 0x59, 0x4B, 0xDD, 0x6D, 0x74, 0x06 };\n        BOOST_CHECK_EQUAL_COLLECTIONS( std::begin( expected_uuid ), std::end( expected_uuid ), &buffer[ 3 ], &buffer[ 17 ] );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( read_char_declaration_buffer_to_small_with_offset_1, simple_char )\n    {\n        const bluetoe::details::attribute char_declaration = attribute_at< cccd_indices, 0, bluetoe::service< suuid >, srv >( 0 );\n        std::uint8_t buffer[ 17 ];\n        auto read = bluetoe::details::attribute_access_arguments::read( buffer, 1 );\n\n        BOOST_CHECK( bluetoe::details::attribute_access_result::success == char_declaration.access( read, 1 ) );\n        BOOST_CHECK_EQUAL( read.buffer_size, 17u );\n        static const std::uint8_t expected_uuid[] = { 0x6B, 0x95, 0x8C, 0xB7, 0x09, 0xA0, 0xCA, 0x89, 0x59, 0x4B, 0xDD, 0x6D, 0x74, 0x06, 0xB1 };\n        BOOST_CHECK_EQUAL_COLLECTIONS( std::begin( expected_uuid ), std::end( expected_uuid ), &buffer[ 2 ], &buffer[ 17 ] );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( the_characteristic_declaration_contains_the_16bit_uuid, short_uuid_char )\n    {\n        const bluetoe::details::attribute char_declaration = attribute_at< cccd_indices, 0, bluetoe::service< suuid >, srv >( 0 );\n        std::uint8_t buffer[ 100 ];\n        auto read = bluetoe::details::attribute_access_arguments::read( buffer, 0 );\n\n        BOOST_CHECK( bluetoe::details::attribute_access_result::success == char_declaration.access( read, 1 ) );\n\n        static const std::uint8_t expected_uuid[] = { 0xB1, 0xD0 };\n        BOOST_CHECK_EQUAL_COLLECTIONS( std::begin( expected_uuid ), std::end( expected_uuid ), &buffer[ 3 ], &buffer[ 5 ] );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( char_declaration_is_not_writable, simple_char )\n    {\n        const bluetoe::details::attribute char_declaration = attribute_at< cccd_indices, 0, bluetoe::service< suuid >, srv >( 0 );\n        std::uint8_t buffer[ 4 ];\n        auto write = bluetoe::details::attribute_access_arguments::write( buffer );\n\n        BOOST_CHECK( char_declaration.access( write, 1 ) == bluetoe::details::attribute_access_result::write_not_permitted );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( read_zero_bytes, simple_char )\n    {\n        const bluetoe::details::attribute char_declaration = attribute_at< cccd_indices, 0, bluetoe::service< suuid >, srv >( 0 );\n        std::uint8_t buffer;\n\n        auto read = bluetoe::details::attribute_access_arguments::read( &buffer, &buffer, 0,\n                        bluetoe::details::client_characteristic_configuration(), bluetoe::connection_security_attributes(), nullptr );\n        auto rc   = char_declaration.access( read, 1 );\n\n        BOOST_CHECK( rc == bluetoe::details::attribute_access_result::success );\n        BOOST_CHECK( read.buffer_size == 0 );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( read_first_single_byte, simple_char )\n    {\n        const bluetoe::details::attribute char_declaration = attribute_at< cccd_indices, 0, bluetoe::service< suuid >, srv >( 0 );\n        std::uint8_t buffer;\n\n        auto read = bluetoe::details::attribute_access_arguments::read( &buffer, &buffer + 1, 0,\n                        bluetoe::details::client_characteristic_configuration(), bluetoe::connection_security_attributes(), nullptr );\n        auto rc   = char_declaration.access( read, 1 );\n\n        BOOST_CHECK( rc == bluetoe::details::attribute_access_result::success );\n        BOOST_CHECK( read.buffer_size == 1 );\n        BOOST_CHECK( buffer == 0x0A ); // property == read + write\n    }\n\n    BOOST_FIXTURE_TEST_CASE( read_two_bytes_second_byte_points_into_the_uuid, simple_char )\n    {\n        const bluetoe::details::attribute char_declaration = attribute_at< cccd_indices, 0, bluetoe::service< suuid >, srv >( 0 );\n        std::uint8_t buffer[ 2 ];\n\n        auto read = bluetoe::details::attribute_access_arguments::read( buffer, 2 );\n        auto rc   = char_declaration.access( read, 1 );\n\n        BOOST_CHECK( rc == bluetoe::details::attribute_access_result::success );\n        BOOST_CHECK( read.buffer_size == 2 );\n        BOOST_CHECK( buffer[ 0 ] == 0x00 ); // hi byte char value handle\n        BOOST_CHECK( buffer[ 1 ] == 0x6B ); // first byte of the uuid\n    }\n\n    BOOST_FIXTURE_TEST_CASE( read_one_byte_from_the_uuid, simple_char )\n    {\n        const bluetoe::details::attribute char_declaration = attribute_at< cccd_indices, 0, bluetoe::service< suuid >, srv >( 0 );\n        std::uint8_t buffer[ 1 ];\n\n        auto read = bluetoe::details::attribute_access_arguments::read( buffer, 4 );\n        auto rc   = char_declaration.access( read, 1 );\n\n        BOOST_CHECK( rc == bluetoe::details::attribute_access_result::success );\n        BOOST_CHECK( read.buffer_size == 1 );\n        BOOST_CHECK( buffer[ 0 ] == 0x95 );\n    }\n\nBOOST_AUTO_TEST_SUITE_END()\n\n\nBOOST_AUTO_TEST_SUITE( characteristic_properties )\n    BOOST_FIXTURE_TEST_CASE( by_default_an_attribute_is_readable_and_writeable, read_characteristic_properties< simple_char > )\n    {\n        BOOST_CHECK( properties & 0x02 );\n        BOOST_CHECK( properties & 0x08 );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( read_only, read_characteristic_properties< simple_const_char > )\n    {\n        BOOST_CHECK( properties & 0x02 );\n        BOOST_CHECK_EQUAL( properties & 0x08, 0 );\n    }\n\n    typedef bluetoe::characteristic<\n            bluetoe::characteristic_uuid< 0xD0B10674, 0x6DDD, 0x4B59, 0x89CA, 0xA009B78C956B >,\n            bluetoe::bind_characteristic_value< std::uint32_t, &simple_value >,\n            bluetoe::no_write_access\n        > simple_char_without_write_access;\n\n    BOOST_FIXTURE_TEST_CASE( write_only, read_characteristic_properties< simple_char_without_write_access > )\n    {\n        BOOST_CHECK( properties & 0x02 );\n        BOOST_CHECK_EQUAL( properties & 0x08, 0 );\n    }\n\n    typedef bluetoe::characteristic<\n            bluetoe::characteristic_uuid< 0xD0B10674, 0x6DDD, 0x4B59, 0x89CA, 0xA009B78C956B >,\n            bluetoe::bind_characteristic_value< std::uint32_t, &simple_value >,\n            bluetoe::no_write_access,\n            bluetoe::no_read_access\n        > simple_char_without_any_access;\n\n    BOOST_FIXTURE_TEST_CASE( only, read_characteristic_properties< simple_char_without_any_access > )\n    {\n        BOOST_CHECK_EQUAL( properties & 0x02, 0 );\n        BOOST_CHECK_EQUAL( properties & 0x08, 0 );\n    }\n\n    typedef bluetoe::characteristic<\n            bluetoe::characteristic_uuid< 0xD0B10674, 0x6DDD, 0x4B59, 0x89CA, 0xA009B78C956B >,\n            bluetoe::bind_characteristic_value< std::uint32_t, &simple_value >,\n            bluetoe::notify\n        > simple_char_with_notification;\n\n    BOOST_FIXTURE_TEST_CASE( with_notify, read_characteristic_properties< simple_char_with_notification > )\n    {\n        BOOST_CHECK_EQUAL( properties & 0x10, 0x10 );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( without_notify, read_characteristic_properties< simple_char > )\n    {\n        BOOST_CHECK_EQUAL( properties & 0x10, 0 );\n    }\n\n    typedef bluetoe::characteristic<\n            bluetoe::characteristic_uuid< 0xD0B10674, 0x6DDD, 0x4B59, 0x89CA, 0xA009B78C956B >,\n            bluetoe::bind_characteristic_value< std::uint32_t, &simple_value >,\n            bluetoe::indicate\n        > simple_char_with_indication;\n\n    BOOST_FIXTURE_TEST_CASE( with_indicate, read_characteristic_properties< simple_char_with_indication > )\n    {\n        BOOST_CHECK_EQUAL( properties & 0x20, 0x20 );\n    }\n\n    typedef bluetoe::characteristic<\n        bluetoe::characteristic_uuid< 0xD0B10674, 0x6DDD, 0x4B59, 0x89CA, 0xA009B78C956B >,\n        bluetoe::bind_characteristic_value< std::uint32_t, &simple_value >,\n        bluetoe::write_without_response\n    > write_without_response_char;\n\n    BOOST_FIXTURE_TEST_CASE( with_write_without_response, read_characteristic_properties< write_without_response_char > )\n    {\n        BOOST_CHECK_EQUAL( properties & 0x04, 0x04 );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( without_write_without_response, read_characteristic_properties< simple_char_with_indication > )\n    {\n        BOOST_CHECK_EQUAL( properties & 0x04, 0x00 );\n    }\n\n    typedef bluetoe::characteristic<\n        bluetoe::characteristic_uuid< 0xD0B10674, 0x6DDD, 0x4B59, 0x89CA, 0xA009B78C956B >,\n        bluetoe::bind_characteristic_value< std::uint32_t, &simple_value >,\n        bluetoe::only_write_without_response,\n        bluetoe::no_read_access\n    > only_write_without_response_char;\n\n    BOOST_FIXTURE_TEST_CASE( only_with_write_without_response, read_characteristic_properties< only_write_without_response_char > )\n    {\n        BOOST_CHECK_EQUAL( properties & 0x04, 0x04 );\n        BOOST_CHECK_EQUAL( properties & 0x08, 0x00 );\n    }\n    typedef bluetoe::characteristic<\n        bluetoe::characteristic_uuid< 0xD0B10674, 0x6DDD, 0x4B59, 0x89CA, 0xA009B78C956B >,\n        bluetoe::bind_characteristic_value< std::uint32_t, &simple_value >,\n        bluetoe::only_write_without_response\n    > only_write_without_response_and_read_char;\n\n    BOOST_FIXTURE_TEST_CASE( only_with_write_without_response_and_read, read_characteristic_properties< only_write_without_response_and_read_char > )\n    {\n        BOOST_CHECK_EQUAL( properties & 0x04, 0x04 );\n        BOOST_CHECK_EQUAL( properties & 0x08, 0x00 );\n        BOOST_CHECK_EQUAL( properties & 0x02, 0x02 );\n    }\n\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE( characteristic_extended_properties )\n\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE( characteristic_user_description )\n\n    char simple_value = 0;\n    static constexpr char name[] = \"Die ist der Name\";\n\n    typedef bluetoe::characteristic<\n        bluetoe::characteristic_name< name >,\n        bluetoe::characteristic_uuid16< 0x0815 >,\n        bluetoe::bind_characteristic_value< char, &simple_value >\n    > named_char;\n\n    BOOST_FIXTURE_TEST_CASE( there_is_an_attribute_with_the_given_name, access_attributes< named_char > )\n    {\n        BOOST_CHECK_EQUAL( 3, int(number_of_attributes) );\n        compare_characteristic( { 'D', 'i', 'e', ' ', 'i', 's', 't', ' ', 'd', 'e', 'r', ' ', 'N', 'a', 'm', 'e' }, 0x2901 );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( characteristic_user_description_is_readable_with_offset, access_attributes< named_char > )\n    {\n        std::uint8_t buffer[ 100 ];\n        auto read = bluetoe::details::attribute_access_arguments::read( buffer, 12 );\n\n        BOOST_REQUIRE( bluetoe::details::attribute_access_result::success == attribute_by_type( 0x2901 ).access( read, 1 ) );\n\n        static const std::uint8_t expected_value[] = { 'N', 'a', 'm', 'e' };\n        BOOST_CHECK_EQUAL_COLLECTIONS( std::begin( expected_value ), std::end( expected_value ), read.buffer, read.buffer + read.buffer_size );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( characteristic_user_description_is_readable_with_offset_16, access_attributes< named_char > )\n    {\n        std::uint8_t buffer[ 100 ];\n        auto read = bluetoe::details::attribute_access_arguments::read( buffer, 16 );\n\n        BOOST_REQUIRE( bluetoe::details::attribute_access_result::success == attribute_by_type( 0x2901 ).access( read, 1 ) );\n        BOOST_CHECK_EQUAL( read.buffer_size, 0u );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( characteristic_user_description_is_not_readable_behind, access_attributes< named_char > )\n    {\n        std::uint8_t buffer[ 100 ];\n        auto read = bluetoe::details::attribute_access_arguments::read( buffer, 17 );\n\n        BOOST_CHECK( bluetoe::details::attribute_access_result::invalid_offset == attribute_by_type( 0x2901 ).access( read, 1 ) );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( is_not_writeable, access_attributes< named_char > )\n    {\n        std::uint8_t buffer[ 100 ];\n\n        auto attr  = attribute_by_type( 0x2901 );\n        auto write = bluetoe::details::attribute_access_arguments::write( buffer );\n\n        BOOST_CHECK( attr.access( write, 1 ) == bluetoe::details::attribute_access_result::write_not_permitted );\n    }\n\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE( client_characteristic_configuration )\n\n    BOOST_FIXTURE_TEST_CASE( does_not_exist_by_default, access_attributes< simple_char > )\n    {\n        BOOST_CHECK( !find_attribute_by_type( 0x2902 ).first );\n    }\n\n    char simple_value = 0;\n\n    typedef bluetoe::characteristic<\n        bluetoe::characteristic_uuid16< 0x0815 >,\n        bluetoe::bind_characteristic_value< char, &simple_value >,\n        bluetoe::notify\n    > notified_char;\n\n    BOOST_FIXTURE_TEST_CASE( exist_when_notification_is_enabled, access_attributes< notified_char > )\n    {\n        BOOST_CHECK( find_attribute_by_type( 0x2902 ).first );\n    }\n\n    typedef bluetoe::characteristic<\n        bluetoe::characteristic_uuid16< 0x0815 >,\n        bluetoe::bind_characteristic_value< char, &simple_value >,\n        bluetoe::notify\n    > indicated_char;\n\n    BOOST_FIXTURE_TEST_CASE( exist_when_indication_is_enabled, access_attributes< indicated_char > )\n    {\n        BOOST_CHECK( find_attribute_by_type( 0x2902 ).first );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( has_3_attributes, notified_char )\n    {\n        BOOST_CHECK_EQUAL( int( number_of_attributes ), 3 );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( number_of_client_configs_is_one, notified_char )\n    {\n        BOOST_CHECK_EQUAL( int( number_of_client_configs ), 1 );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( characteristic_can_be_written, access_attributes< notified_char > )\n    {\n        static const std::uint8_t bytes_to_write[] = { 0x01, 0x00 };\n\n        auto write = bluetoe::details::attribute_access_arguments::write( bytes_to_write, 0, client_configurations() );\n        auto rc    = attribute_by_type( 0x2902 ).access( write, 0 );\n\n        BOOST_CHECK( rc == bluetoe::details::attribute_access_result::success );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( characteristic_can_be_written_to_small, access_attributes< notified_char > )\n    {\n        static const std::uint8_t bytes_to_write[] = { 0x01 };\n\n        auto write = bluetoe::details::attribute_access_arguments::write( bytes_to_write, 0, client_configurations() );\n        auto rc    = attribute_by_type( 0x2902 ).access( write, 0 );\n\n        BOOST_CHECK( rc == bluetoe::details::attribute_access_result::success );\n\n        compare_characteristic( { 0x01, 0x00 }, 0x2902 );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( characteristic_cant_be_written_to_large, access_attributes< notified_char > )\n    {\n        static const std::uint8_t bytes_to_write[] = { 0x01, 0x02, 0x03 };\n\n        auto write = bluetoe::details::attribute_access_arguments::write( bytes_to_write, 0, client_configurations() );\n        auto rc    = attribute_by_type( 0x2902 ).access( write, 0 );\n\n        BOOST_CHECK( rc == bluetoe::details::attribute_access_result::invalid_attribute_value_length );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( and_be_read, access_attributes< notified_char > )\n    {\n        static const std::uint8_t bytes_to_write[] = { 0x03, 0x00 };\n\n        auto write = bluetoe::details::attribute_access_arguments::write( bytes_to_write, 0, client_configurations() );\n        BOOST_REQUIRE( attribute_by_type( 0x2902 ).access( write, 0 ) == bluetoe::details::attribute_access_result::success );\n\n        compare_characteristic( { 0x03, 0x00 }, 0x2902 );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( and_be_read_with_offset, access_attributes< notified_char > )\n    {\n        static const std::uint8_t bytes_to_write[] = { 0x03, 0x00 };\n\n        auto write = bluetoe::details::attribute_access_arguments::write( bytes_to_write, 0, client_configurations() );\n        BOOST_REQUIRE( attribute_by_type( 0x2902 ).access( write, 0 ) == bluetoe::details::attribute_access_result::success );\n\n        std::uint8_t buffer[ 10 ];\n        auto read = bluetoe::details::attribute_access_arguments::read( buffer, 1, client_configurations() );\n        auto rc   = attribute_by_type( 0x2902 ).access( read, 0 );\n\n        BOOST_CHECK( rc == bluetoe::details::attribute_access_result::success );\n        BOOST_CHECK_EQUAL( read.buffer_size, 1u );\n        BOOST_CHECK_EQUAL( read.buffer[ 0 ], 0u );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( and_be_read_with_offset_equal_size, access_attributes< notified_char > )\n    {\n        static const std::uint8_t bytes_to_write[] = { 0x03, 0x00 };\n\n        auto write = bluetoe::details::attribute_access_arguments::write( bytes_to_write, 0, client_configurations() );\n        BOOST_REQUIRE( attribute_by_type( 0x2902 ).access( write, 0 ) == bluetoe::details::attribute_access_result::success );\n\n        std::uint8_t buffer[ 10 ];\n        auto read = bluetoe::details::attribute_access_arguments::read( buffer, 2, client_configurations() );\n        auto rc   = attribute_by_type( 0x2902 ).access( read, 0 );\n\n        BOOST_CHECK( rc == bluetoe::details::attribute_access_result::success );\n        BOOST_CHECK_EQUAL( read.buffer_size, 0u );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( and_be_read_with_offset_out_of_range, access_attributes< notified_char > )\n    {\n        static const std::uint8_t bytes_to_write[] = { 0x03, 0x00 };\n\n        auto write = bluetoe::details::attribute_access_arguments::write( bytes_to_write, 0, client_configurations() );\n        BOOST_REQUIRE( attribute_by_type( 0x2902 ).access( write, 0 ) == bluetoe::details::attribute_access_result::success );\n\n        std::uint8_t buffer[ 10 ];\n        auto read = bluetoe::details::attribute_access_arguments::read( buffer, 3, client_configurations() );\n        auto rc   = attribute_by_type( 0x2902 ).access( read, 0 );\n\n        BOOST_CHECK( rc == bluetoe::details::attribute_access_result::invalid_offset );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( write_only_the_last_byte, access_attributes< notified_char > )\n    {\n        static const std::uint8_t bytes_to_write[] = { 0xff };\n\n        auto write = bluetoe::details::attribute_access_arguments::write( bytes_to_write, 1, client_configurations() );\n        BOOST_REQUIRE( attribute_by_type( 0x2902 ).access( write, 0 ) == bluetoe::details::attribute_access_result::success );\n\n        // write will be ignored\n        compare_characteristic( { 0x00, 0x00 }, 0x2902 );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( write_zero_bytes_at_the_end, access_attributes< notified_char > )\n    {\n        static const std::uint8_t byte = 0;\n\n        auto write = bluetoe::details::attribute_access_arguments::write( &byte, &byte, 2,\n            client_configurations(), bluetoe::connection_security_attributes(), nullptr );\n        BOOST_REQUIRE( attribute_by_type( 0x2902 ).access( write, 0 ) == bluetoe::details::attribute_access_result::success );\n\n        // write as no effect\n        compare_characteristic( { 0x00, 0x00 }, 0x2902 );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( write_over_the_end, access_attributes< notified_char > )\n    {\n        static const std::uint8_t byte = 0;\n\n        auto write = bluetoe::details::attribute_access_arguments::write( &byte, &byte + 1, 2,\n                        client_configurations(), bluetoe::connection_security_attributes(), nullptr );\n        BOOST_REQUIRE( attribute_by_type( 0x2902 ).access( write, 0 ) == bluetoe::details::attribute_access_result::invalid_attribute_value_length );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( write_behind_the_end, access_attributes< notified_char > )\n    {\n        static const std::uint8_t byte = 0;\n\n        auto write = bluetoe::details::attribute_access_arguments::write( &byte, &byte + 1, 3,\n                        client_configurations(), bluetoe::connection_security_attributes(), nullptr );\n        BOOST_REQUIRE( attribute_by_type( 0x2902 ).access( write, 0 ) == bluetoe::details::attribute_access_result::invalid_offset );\n    }\n\n    typedef bluetoe::characteristic<\n        bluetoe::characteristic_uuid16< 0x0815 >,\n        bluetoe::bind_characteristic_value< char, &simple_value >,\n        bluetoe::requires_encryption,\n        bluetoe::notify\n    > indicated_char_requires_encryption;\n\n    BOOST_FIXTURE_TEST_CASE( write_requires_encryption_insufficient_authentication, access_attributes< indicated_char_requires_encryption > )\n    {\n        static const std::uint8_t bytes_to_write[] = { 0x01, 0x00 };\n\n        auto write = bluetoe::details::attribute_access_arguments::write( bytes_to_write, 0, client_configurations(),\n            bluetoe::connection_security_attributes( false, bluetoe::device_pairing_status::no_key ) );\n        auto rc    = attribute_by_type( 0x2902 ).access( write, 0 );\n\n        BOOST_CHECK( rc == bluetoe::details::attribute_access_result::insufficient_authentication );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( write_requires_encryption_insufficient_encryption, access_attributes< indicated_char_requires_encryption > )\n    {\n        static const std::uint8_t bytes_to_write[] = { 0x01, 0x00 };\n\n        auto write = bluetoe::details::attribute_access_arguments::write( bytes_to_write, 0, client_configurations(),\n            bluetoe::connection_security_attributes( false, bluetoe::device_pairing_status::unauthenticated_key ) );\n        auto rc    = attribute_by_type( 0x2902 ).access( write, 0 );\n\n        BOOST_CHECK( rc == bluetoe::details::attribute_access_result::insufficient_encryption );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( write_requires_encryption_success, access_attributes< indicated_char_requires_encryption > )\n    {\n        static const std::uint8_t bytes_to_write[] = { 0x01, 0x00 };\n\n        auto write = bluetoe::details::attribute_access_arguments::write( bytes_to_write, 0, client_configurations(),\n            bluetoe::connection_security_attributes( true, bluetoe::device_pairing_status::unauthenticated_key ) );\n        auto rc    = attribute_by_type( 0x2902 ).access( write, 0 );\n\n        BOOST_CHECK( rc == bluetoe::details::attribute_access_result::success );\n    }\n\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE( server_characteristic_configuration )\n\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE( characteristic_presentation_format )\n\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE( characteristic_aggregate_format )\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "tests/characteristic_value_tests.cpp",
    "content": "#include <bluetoe/characteristic.hpp>\n#include <bluetoe/service.hpp>\n#include <bluetoe/encryption.hpp>\n#include <bluetoe/client_characteristic_configuration.hpp>\n\n#define BOOST_TEST_MODULE\n#include <boost/test/included/unit_test.hpp>\n#include \"hexdump.hpp\"\n#include \"test_attribute_access.hpp\"\n#include \"test_characteristics.hpp\"\n#include <boost/mpl/list.hpp>\n\nusing cccd_indices = std::tuple<>;\nusing suuid = bluetoe::service_uuid16< 0x4711 >;\n\nusing srv = bluetoe::server<>;\n\nBOOST_AUTO_TEST_SUITE( characteristic_value_access )\n\n    BOOST_FIXTURE_TEST_CASE( simple_value_can_be_read, simple_char )\n    {\n        const bluetoe::details::attribute value_attribute = attribute_at< cccd_indices, 0, bluetoe::service< suuid >, srv >( 1 );\n        std::uint8_t buffer[ 100 ];\n        auto read = bluetoe::details::attribute_access_arguments::read( buffer, 0 );\n\n        BOOST_REQUIRE( bluetoe::details::attribute_access_result::success == value_attribute.access( read, 1 ) );\n\n        static const std::uint8_t expected_value[] = { 0xdd, 0xcc, 0xbb, 0xaa };\n        BOOST_CHECK_EQUAL_COLLECTIONS( std::begin( expected_value ), std::end( expected_value ), read.buffer, read.buffer + read.buffer_size );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( char_value_returns_invalid_offset_when_read_behind_the_data, simple_char )\n    {\n        const bluetoe::details::attribute value_attribute = attribute_at< cccd_indices, 0, bluetoe::service< suuid >, srv >( 1 );\n        std::uint8_t buffer[ 100 ];\n        auto read = bluetoe::details::attribute_access_arguments::read( buffer, 5 );\n\n        BOOST_CHECK( bluetoe::details::attribute_access_result::invalid_offset == value_attribute.access( read, 1 ) );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( simple_value_can_be_read_with_offset, simple_char )\n    {\n        const bluetoe::details::attribute value_attribute = attribute_at< cccd_indices, 0, bluetoe::service< suuid >, srv >( 1 );\n        std::uint8_t buffer[ 100 ];\n        auto read = bluetoe::details::attribute_access_arguments::read( buffer, 2 );\n\n        BOOST_REQUIRE( bluetoe::details::attribute_access_result::success == value_attribute.access( read, 1 ) );\n\n        static const std::uint8_t expected_value[] = { 0xbb, 0xaa };\n        BOOST_CHECK_EQUAL_COLLECTIONS( std::begin( expected_value ), std::end( expected_value ), read.buffer, read.buffer + read.buffer_size );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( simple_value_can_be_read_with_offset_equal_to_length, simple_char )\n    {\n        const bluetoe::details::attribute value_attribute = attribute_at< cccd_indices, 0, bluetoe::service< suuid >, srv >( 1 );\n        std::uint8_t buffer[ 100 ];\n        auto read = bluetoe::details::attribute_access_arguments::read( buffer, 4 );\n\n        BOOST_REQUIRE( bluetoe::details::attribute_access_result::success == value_attribute.access( read, 1 ) );\n        BOOST_CHECK_EQUAL( read.buffer_size, 0u );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( simple_value_can_be_written, simple_char )\n    {\n        const bluetoe::details::attribute value_attribute = attribute_at< cccd_indices, 0, bluetoe::service< suuid >, srv >( 1 );\n        std::uint8_t new_value[] = { 0x01, 0x02, 0x03, 0x04 };\n\n        auto write = bluetoe::details::attribute_access_arguments::write( new_value );\n\n        BOOST_REQUIRE( bluetoe::details::attribute_access_result::success == value_attribute.access( write, 1 ) );\n\n        std::uint8_t buffer[ 4 ];\n        auto read = bluetoe::details::attribute_access_arguments::read( buffer, 0 );\n\n        BOOST_REQUIRE( bluetoe::details::attribute_access_result::success == value_attribute.access( read, 1 ) );\n\n        static const std::uint8_t expected_value[] = { 0x01, 0x02, 0x03, 0x04 };\n        BOOST_CHECK_EQUAL_COLLECTIONS( std::begin( expected_value ), std::end( expected_value ), read.buffer, read.buffer + read.buffer_size );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( simple_const_value_can_be_read, simple_const_char )\n    {\n        const bluetoe::details::attribute value_attribute = attribute_at< cccd_indices, 0, bluetoe::service< suuid >, srv >( 1 );\n        std::uint8_t buffer[ 100 ];\n        auto read = bluetoe::details::attribute_access_arguments::read( buffer, 0 );\n\n        BOOST_REQUIRE( bluetoe::details::attribute_access_result::success == value_attribute.access( read, 1 ) );\n\n        static const std::uint8_t expected_value[] = { 0xdd, 0xcc, 0xbb, 0xaa };\n        BOOST_CHECK_EQUAL_COLLECTIONS( std::begin( expected_value ), std::end( expected_value ), read.buffer, read.buffer + read.buffer_size );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( simple_const_value_can_not_be_writte, simple_const_char )\n    {\n        const bluetoe::details::attribute value_attribute = attribute_at< cccd_indices, 0, bluetoe::service< suuid >, srv >( 1 );\n        std::uint8_t new_value[] = { 0x01, 0x02, 0x03, 0x04 };\n\n        auto write = bluetoe::details::attribute_access_arguments::write( new_value );\n\n        BOOST_REQUIRE( bluetoe::details::attribute_access_result::write_not_permitted == value_attribute.access( write, 1 ) );\n    }\n\n    BOOST_AUTO_TEST_CASE( simple_value_without_read_access_can_not_be_read )\n    {\n        bluetoe::characteristic<\n            bluetoe::characteristic_uuid< 0xD0B10674, 0x6DDD, 0x4B59, 0x89CA, 0xA009B78C956B >,\n            bluetoe::bind_characteristic_value< std::uint32_t, &simple_value >,\n            bluetoe::no_read_access\n        > simple_char_without_write_access;\n\n        const bluetoe::details::attribute value_attribute = simple_char_without_write_access.attribute_at< cccd_indices, 0, bluetoe::service< suuid >, srv >( 1 );\n\n        std::uint8_t old_value[ 4 ];\n\n        auto read = bluetoe::details::attribute_access_arguments::read( old_value, 0 );\n\n        BOOST_REQUIRE( bluetoe::details::attribute_access_result::read_not_permitted == value_attribute.access( read, 1 ) );\n    }\n\n    BOOST_AUTO_TEST_CASE( simple_value_without_write_access_can_not_be_written )\n    {\n        bluetoe::characteristic<\n            bluetoe::characteristic_uuid< 0xD0B10674, 0x6DDD, 0x4B59, 0x89CA, 0xA009B78C956B >,\n            bluetoe::bind_characteristic_value< std::uint32_t, &simple_value >,\n            bluetoe::no_write_access\n        > simple_char_without_read_access;\n\n        const bluetoe::details::attribute value_attribute = simple_char_without_read_access.attribute_at< cccd_indices, 0, bluetoe::service< suuid >, srv >( 1 );\n\n        std::uint8_t new_value[] = { 0x01, 0x02, 0x03, 0x04 };\n\n        auto write = bluetoe::details::attribute_access_arguments::write( new_value );\n\n        BOOST_REQUIRE( bluetoe::details::attribute_access_result::write_not_permitted == value_attribute.access( write, 1 ) );\n    }\n\n    static std::uint32_t write_to_large_value = 15;\n\n    BOOST_AUTO_TEST_CASE( write_to_large )\n    {\n        bluetoe::characteristic<\n            bluetoe::characteristic_uuid< 0xD0B10674, 0x6DDD, 0x4B59, 0x89CA, 0xA009B78C956B >,\n            bluetoe::bind_characteristic_value< std::uint32_t, &write_to_large_value >\n        > characteristic;\n\n        std::uint8_t new_value[] = { 0x01, 0x02, 0x03, 0x04, 0x05 };\n\n        auto write = bluetoe::details::attribute_access_arguments::write( new_value );\n\n        BOOST_REQUIRE( ( bluetoe::details::attribute_access_result::invalid_attribute_value_length == characteristic.attribute_at< cccd_indices, 0, bluetoe::service< suuid >, srv >( 1 ).access( write, 1 ) ) );\n        BOOST_CHECK_EQUAL( write_to_large_value, 15u );\n    }\n\n    std::uint8_t writable_value[ 4 ] = { 0x01, 0x02, 0x03, 0x04 };\n\n    struct writable_value_char :\n        bluetoe::characteristic<\n            bluetoe::characteristic_uuid< 0xD0B10674, 0x6DDD, 0x4B59, 0x89CA, 0xA009B78C956B >,\n            bluetoe::bind_characteristic_value< decltype( writable_value ), &writable_value >\n        >\n    {\n        writable_value_char()\n        {\n            static const std::uint8_t init_value[ 4 ] = { 0x01, 0x02, 0x03, 0x04 };\n            std::copy( std::begin( init_value ), std::end( init_value ), std::begin( writable_value ) );\n        }\n    };\n\n    BOOST_FIXTURE_TEST_CASE( write_with_offset, writable_value_char )\n    {\n        static const std::uint8_t new_value[] = { 0x22, 0x33 };\n        auto write = bluetoe::details::attribute_access_arguments::write( new_value, 1 );\n        auto rc    = attribute_at< cccd_indices, 0, bluetoe::service< suuid >, srv >( 1 ).access( write, 1 );\n\n        BOOST_CHECK( rc == bluetoe::details::attribute_access_result::success );\n        static const std::uint8_t expected_value[] = { 0x01, 0x22, 0x33, 0x04 };\n        BOOST_CHECK_EQUAL_COLLECTIONS( std::begin( writable_value ), std::end( writable_value ), std::begin( expected_value ), std::end( expected_value ) );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( write_over_end_with_offset, writable_value_char )\n    {\n        static const std::uint8_t new_value[] = { 0x22, 0x33 };\n        auto write = bluetoe::details::attribute_access_arguments::write( new_value, 3 );\n        auto rc    = attribute_at< cccd_indices, 0, bluetoe::service< suuid >, srv >( 1 ).access( write, 1 );\n\n        BOOST_CHECK( rc == bluetoe::details::attribute_access_result::invalid_attribute_value_length );\n        static const std::uint8_t expected_value[] = { 0x01, 0x02, 0x03, 0x04 };\n        BOOST_CHECK_EQUAL_COLLECTIONS( std::begin( writable_value ), std::end( writable_value ), std::begin( expected_value ), std::end( expected_value ) );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( write_behind_the_end, writable_value_char )\n    {\n        static const std::uint8_t new_value[] = { 0x22, 0x33 };\n        auto write = bluetoe::details::attribute_access_arguments::write( new_value, 5 );\n        auto rc    = attribute_at< cccd_indices, 0, bluetoe::service< suuid >, srv >( 1 ).access( write, 1 );\n\n        BOOST_CHECK( rc == bluetoe::details::attribute_access_result::invalid_offset );\n        static const std::uint8_t expected_value[] = { 0x01, 0x02, 0x03, 0x04 };\n        BOOST_CHECK_EQUAL_COLLECTIONS( std::begin( writable_value ), std::end( writable_value ), std::begin( expected_value ), std::end( expected_value ) );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( can_write_zero_bytes_at_the_end, writable_value_char )\n    {\n        std::uint8_t c;\n        auto write = bluetoe::details::attribute_access_arguments::write( &c, &c, 4,\n            bluetoe::details::client_characteristic_configuration(),\n            bluetoe::connection_security_attributes(),\n            nullptr );\n        auto rc    = attribute_at< cccd_indices, 0, bluetoe::service< suuid >, srv >( 1 ).access( write, 1 );\n        BOOST_CHECK( rc == bluetoe::details::attribute_access_result::success );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( can_write_last_byte, writable_value_char )\n    {\n        std::uint8_t c = 0xff;\n        auto write = bluetoe::details::attribute_access_arguments::write( &c, &c + 1, 3,\n            bluetoe::details::client_characteristic_configuration(),\n            bluetoe::connection_security_attributes(),\n            nullptr );\n        auto rc    = attribute_at< cccd_indices, 0, bluetoe::service< suuid >, srv >( 1 ).access( write, 1 );\n\n        BOOST_CHECK( rc == bluetoe::details::attribute_access_result::success );\n        static const std::uint8_t expected_value[] = { 0x01, 0x02, 0x03, 0xff };\n        BOOST_CHECK_EQUAL_COLLECTIONS( std::begin( writable_value ), std::end( writable_value ), std::begin( expected_value ), std::end( expected_value ) );\n    }\n\nBOOST_AUTO_TEST_SUITE_END()\n\n\nBOOST_AUTO_TEST_SUITE( fixed_value_tests )\n\n    typedef bluetoe::characteristic<\n        bluetoe::characteristic_uuid16< 0xD0B1 >,\n        bluetoe::fixed_value< std::uint16_t, 0x0815 >\n    > fixed_16bit;\n\n    typedef bluetoe::characteristic<\n        bluetoe::characteristic_uuid16< 0xD0B1 >,\n        bluetoe::fixed_value< std::int32_t, 0x08151213 >\n    > fixed_32bit;\n\n    BOOST_FIXTURE_TEST_CASE( find_char, access_attributes< fixed_16bit > )\n    {\n        attribute_by_type( 0xD0B1 );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( properties_are_read_only, read_characteristic_properties< fixed_16bit > )\n    {\n        BOOST_CHECK_EQUAL( properties, 0x02 );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( read_value, access_attributes< fixed_16bit > )\n    {\n        compare_characteristic( { 0x15, 0x08 }, 0xd0b1 );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( read_only, access_attributes< fixed_32bit > )\n    {\n        const auto attr = attribute_by_type( 0xD0B1 );\n        std::uint8_t buffer[ 4 ];\n        auto write = bluetoe::details::attribute_access_arguments::write( buffer );\n\n        BOOST_CHECK( attr.access( write, 1 ) == bluetoe::details::attribute_access_result::write_not_permitted );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( read_with_offset, access_attributes< fixed_32bit > )\n    {\n        BOOST_CHECK( read_attribute_at( { 0x12, 0x15, 0x08 }, 1, 1, 3 )\n            == bluetoe::details::attribute_access_result::success );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( read_truncated_with_offset, access_attributes< fixed_32bit > )\n    {\n        BOOST_CHECK( read_attribute_at( { 0x12, 0x15 }, 1, 1, 2 )\n            == bluetoe::details::attribute_access_result::success );\n    }\n\n    typedef bluetoe::characteristic<\n        bluetoe::characteristic_uuid16< 0xD0B1 >,\n        bluetoe::fixed_value< std::int32_t, 0x08151213 >,\n        bluetoe::no_read_access\n    > fixed_without_read_access;\n\n    BOOST_FIXTURE_TEST_CASE( read_without_read_access, access_attributes< fixed_without_read_access > )\n    {\n        const auto attr = attribute_by_type( 0xD0B1 );\n        std::uint8_t buffer[ 4 ];\n        auto read = bluetoe::details::attribute_access_arguments::read( buffer, 0 );\n\n        BOOST_CHECK( attr.access( read, 1 ) == bluetoe::details::attribute_access_result::read_not_permitted );\n    }\n\n    typedef bluetoe::characteristic<\n        bluetoe::characteristic_uuid16< 0xD0B1 >,\n        bluetoe::fixed_value< std::int32_t, 0x08151213 >,\n        bluetoe::notify\n    > fixed_notifiable;\n\n    BOOST_FIXTURE_TEST_CASE( fixed_notifiable_must_have_a_client_characteristic_configuration, access_attributes< fixed_notifiable > )\n    {\n        attribute_by_type( 0x2902 );\n    }\n\nBOOST_AUTO_TEST_SUITE_END()\n\nnamespace {\n    const std::uint8_t test_blob[] = { 0x00, 0x12, 0x00, 0xab, 0x05 };\n}\n\nBOOST_AUTO_TEST_SUITE( fixed_blob_tests )\n\n\n    using blob_char = bluetoe::characteristic<\n        bluetoe::characteristic_uuid16< 0xD0B1 >,\n        bluetoe::fixed_blob_value< test_blob, sizeof( test_blob ) >\n    >;\n\n    BOOST_FIXTURE_TEST_CASE( read_only_attribute, read_characteristic_properties< blob_char > )\n    {\n        BOOST_CHECK_EQUAL( properties, 0x02 );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( read_value, access_attributes< blob_char > )\n    {\n        compare_characteristic( { 0x00, 0x12, 0x00, 0xab, 0x05 }, 0xd0b1 );\n    }\n\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE( encryption_tests )\n\n    using fixed_value = bluetoe::characteristic<\n        bluetoe::requires_encryption,\n        bluetoe::characteristic_uuid16< 0xD0B1 >,\n        bluetoe::fixed_value< std::int8_t, 42 >\n    >;\n\n    std::uint8_t dummy_value = 43;\n\n    using bound_value = bluetoe::characteristic<\n        bluetoe::requires_encryption,\n        bluetoe::characteristic_uuid16< 0xD0B1 >,\n        bluetoe::bind_characteristic_value< std::uint8_t, &dummy_value >\n    >;\n\n    struct cstring_holder {\n        static constexpr const char* value() {\n            return \"Hallo\";\n        }\n\n        static constexpr std::size_t size() {\n            return 5u;\n        }\n    };\n\n    using cstring_value = bluetoe::characteristic<\n        bluetoe::requires_encryption,\n        bluetoe::characteristic_uuid16< 0xD0B1 >,\n        bluetoe::cstring_wrapper< cstring_holder >\n    >;\n\n    static std::uint8_t test_handler( std::size_t /* read_size */, std::uint8_t* out_buffer, std::size_t& out_size )\n    {\n        *out_buffer = 44;\n        out_size    = 1;\n\n        return bluetoe::error_codes::success;\n    }\n\n    /*\n     * All other handlers share the same base implementation\n     */\n    using other_handlers = bluetoe::characteristic<\n        bluetoe::requires_encryption,\n        bluetoe::characteristic_uuid16< 0xD0B1 >,\n        bluetoe::free_read_handler< test_handler >\n    >;\n\n    using characteristic_types = boost::mpl::list< fixed_value, bound_value, cstring_value, other_handlers >;\n\n    BOOST_AUTO_TEST_SUITE( unpaired_unencrypted )\n\n        BOOST_AUTO_TEST_CASE_TEMPLATE( authentication_required, char_t, characteristic_types )\n        {\n            access_attributes< char_t > c;\n\n            BOOST_CHECK_EQUAL(\n                static_cast< int >( c.read_attribute_at( {}, 1, 0, 23 ) ),\n                static_cast< int >( bluetoe::error_codes::insufficient_authentication ) );\n        }\n\n        BOOST_AUTO_TEST_CASE_TEMPLATE( make_sure_access_rights_are_tested_first, char_t, characteristic_types )\n        {\n            access_attributes< char_t > c;\n\n            BOOST_CHECK_EQUAL(\n                static_cast< int >( c.write_attribute_at( { 0x11 } ) ),\n                static_cast< int >( bluetoe::error_codes::insufficient_authentication ) );\n        }\n\n    BOOST_AUTO_TEST_SUITE_END()\n\n\n    BOOST_AUTO_TEST_SUITE( paired_unencrypted )\n\n        static const auto paired_unencrypted_sec = bluetoe::connection_security_attributes( false, bluetoe::device_pairing_status::unauthenticated_key );\n\n        BOOST_AUTO_TEST_CASE_TEMPLATE( authentication_required, char_t, characteristic_types )\n        {\n            access_attributes< char_t > c( paired_unencrypted_sec );\n\n            BOOST_CHECK_EQUAL(\n                static_cast< int >( c.read_attribute_at( {}, 1, 0, 23 ) ),\n                static_cast< int >( bluetoe::error_codes::insufficient_encryption ) );\n        }\n\n        BOOST_AUTO_TEST_CASE_TEMPLATE( make_sure_access_rights_are_tested_first, char_t, characteristic_types )\n        {\n            access_attributes< char_t > c( paired_unencrypted_sec );\n\n            BOOST_CHECK_EQUAL(\n                static_cast< int >( c.write_attribute_at( { 0x11 } ) ),\n                static_cast< int >( bluetoe::error_codes::insufficient_encryption ) );\n        }\n\n    BOOST_AUTO_TEST_SUITE_END()\n\n    BOOST_AUTO_TEST_SUITE( paired_encrypted )\n\n        static const auto paired_encrypted_sec = bluetoe::connection_security_attributes( true, bluetoe::device_pairing_status::unauthenticated_key );\n\n        template < class Char >\n        struct paired_encrypted_access_attributes : access_attributes< Char > {\n            paired_encrypted_access_attributes() : access_attributes< Char >( paired_encrypted_sec )\n            {}\n        };\n\n        BOOST_FIXTURE_TEST_CASE( reading_fixed_value, paired_encrypted_access_attributes< fixed_value > )\n        {\n            BOOST_CHECK_EQUAL(\n                static_cast< int >( read_attribute_at( { 42 }, 1, 0, 23 ) ),\n                static_cast< int >( bluetoe::error_codes::success ) );\n        }\n\n        BOOST_FIXTURE_TEST_CASE( reading_bound_value, paired_encrypted_access_attributes< bound_value > )\n        {\n            BOOST_CHECK_EQUAL(\n                static_cast< int >( read_attribute_at( { 43 }, 1, 0, 23 ) ),\n                static_cast< int >( bluetoe::error_codes::success ) );\n        }\n\n        BOOST_FIXTURE_TEST_CASE( reading_const_string_value, paired_encrypted_access_attributes< cstring_value > )\n        {\n            BOOST_CHECK_EQUAL(\n                static_cast< int >( read_attribute_at( { 'H', 'a', 'l', 'l', 'o' }, 1, 0, 23 ) ),\n                static_cast< int >( bluetoe::error_codes::success ) );\n        }\n\n        BOOST_FIXTURE_TEST_CASE( reading_other_handlers_value, paired_encrypted_access_attributes< other_handlers > )\n        {\n            BOOST_CHECK_EQUAL(\n                static_cast< int >( read_attribute_at( { 44 }, 1, 0, 23 ) ),\n                static_cast< int >( bluetoe::error_codes::success ) );\n        }\n\n    BOOST_AUTO_TEST_SUITE_END()\n\n    BOOST_AUTO_TEST_SUITE( may_require_encrytion_tests )\n\n        using maybe_char = bluetoe::characteristic<\n            bluetoe::may_require_encryption,\n            bluetoe::characteristic_uuid16< 0xD0B1 >,\n            bluetoe::free_read_handler< test_handler >\n        >;\n\n        BOOST_AUTO_TEST_CASE( read_maybe_encrypted )\n        {\n            access_attributes< maybe_char > c;\n\n            BOOST_CHECK_EQUAL(\n                static_cast< int >( c.read_attribute_at( { 44 }, 1, 0, 23 ) ),\n                static_cast< int >( bluetoe::error_codes::success ) );\n        }\n\n    BOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "tests/connect.coffee",
    "content": "noble = require('noble')\n\nnoble.on 'discover', (peripheral)->\n    console.log \"peripheral discovered: #{peripheral}\"\n\n    if peripheral.id == 'c57821f91dd84fee81bc3f839557fecf'\n\n        console.log 'connecting....'\n        peripheral.connect (error)->\n            if ( error )\n                console.log \"error connecting: #{error}\"\n            else\n                console.log \"connected..\"\n\n                peripheral.on 'disconnect', ->\n                    console.log \"disconnected!\"\n                    console.log \"Scanning\"\n                    noble.startScanning()\n\nnoble.on 'stateChange', (state)->\n    if state == 'poweredOn'\n        console.log \"Scanning\"\n        noble.startScanning()\n\n\n\n"
  },
  {
    "path": "tests/encryption_tests.cpp",
    "content": "#define BOOST_TEST_MODULE\n#include <boost/test/included/unit_test.hpp>\n\n#include <bluetoe/encryption.hpp>\n#include <bluetoe/server.hpp>\n\nusing service_uuid      = bluetoe::service_uuid16< 0x1234 >;\nusing service_uuid_a    = service_uuid;\nusing service_uuid_b    = bluetoe::service_uuid16< 0x1235 >;\nusing service_uuid_c    = bluetoe::service_uuid16< 0x1236 >;\n\nusing char_uuid         = bluetoe::characteristic_uuid16< 0x1234 >;\nusing char_uuid_1       = char_uuid;\nusing char_uuid_2       = bluetoe::characteristic_uuid16< 0x1235 >;\nusing char_uuid_3       = bluetoe::characteristic_uuid16< 0x1236 >;\n\nstd::int32_t dummy_val;\n\nusing char_1 = bluetoe::characteristic<\n    bluetoe::bind_characteristic_value< decltype( dummy_val ), &dummy_val >,\n    char_uuid\n>;\n\nBOOST_AUTO_TEST_CASE( by_default_no_encryption_is_required )\n{\n    using service = bluetoe::service<\n        service_uuid,\n        char_1\n    >;\n\n    using server = bluetoe::server< service >;\n\n    BOOST_CHECK( !bluetoe::details::requires_encryption_support_t< server >::value );\n    BOOST_CHECK(( !bluetoe::details::characteristic_requires_encryption< char_1, service, server >::value ));\n}\n\nBOOST_AUTO_TEST_CASE( encryption_as_default_on_server_level )\n{\n    using service = bluetoe::service<\n        service_uuid,\n        char_1\n    >;\n\n    using server = bluetoe::server<\n        bluetoe::requires_encryption,\n        service\n    >;\n\n    BOOST_CHECK( bluetoe::details::requires_encryption_support_t< server >::value );\n    BOOST_CHECK(( bluetoe::details::characteristic_requires_encryption< char_1, service, server >::value ));\n}\n\nBOOST_AUTO_TEST_CASE( no_encryption_as_default_on_server_level )\n{\n    using service = bluetoe::service<\n        service_uuid,\n        char_1\n    >;\n\n    using server = bluetoe::server<\n        bluetoe::no_encryption_required,\n        service\n    >;\n\n\n    BOOST_CHECK( !bluetoe::details::requires_encryption_support_t< server >::value );\n    BOOST_CHECK(( !bluetoe::details::characteristic_requires_encryption< char_1, service, server >::value ));\n}\n\nBOOST_AUTO_TEST_CASE( a_service_requires_encryption )\n{\n    using service = bluetoe::service<\n        bluetoe::requires_encryption,\n        service_uuid,\n        char_1\n    >;\n\n    using server = bluetoe::server<\n        bluetoe::no_encryption_required,\n        service\n    >;\n\n    BOOST_CHECK( bluetoe::details::requires_encryption_support_t< server >::value );\n    BOOST_CHECK(( bluetoe::details::characteristic_requires_encryption< char_1, service, server >::value ));\n}\n\nBOOST_AUTO_TEST_CASE( all_services_requires_encryption )\n{\n    using service_1 = bluetoe::service<\n        bluetoe::requires_encryption,\n        service_uuid_a,\n        char_1\n    >;\n\n    using service_2 = bluetoe::service<\n        bluetoe::requires_encryption,\n        service_uuid_b,\n        char_1\n    >;\n\n    using server = bluetoe::server<\n        bluetoe::no_encryption_required,\n        service_1,\n        service_2\n    >;\n\n    BOOST_CHECK( bluetoe::details::requires_encryption_support_t< server >::value );\n    BOOST_CHECK(( bluetoe::details::characteristic_requires_encryption< char_1, service_1, server >::value ));\n    BOOST_CHECK(( bluetoe::details::characteristic_requires_encryption< char_1, service_2, server >::value ));\n}\n\nBOOST_AUTO_TEST_CASE( some_services_requires_encryption )\n{\n    using service_1 = bluetoe::service<\n        service_uuid_a,\n        char_1\n    >;\n\n    using service_2 = bluetoe::service<\n        bluetoe::requires_encryption,\n        service_uuid_b,\n        char_1\n    >;\n\n    using server = bluetoe::server<\n        bluetoe::no_encryption_required,\n        service_1,\n        service_2\n    >;\n\n    BOOST_CHECK( bluetoe::details::requires_encryption_support_t< server >::value );\n    BOOST_CHECK(( !bluetoe::details::characteristic_requires_encryption< char_1, service_1, server >::value ));\n    BOOST_CHECK(( bluetoe::details::characteristic_requires_encryption< char_1, service_2, server >::value ));\n}\n\nBOOST_AUTO_TEST_CASE( some_services_requires_encryption_some_not )\n{\n    using service_1 = bluetoe::service<\n        bluetoe::no_encryption_required,\n        service_uuid_a,\n        char_1\n    >;\n\n    using service_2 = bluetoe::service<\n        bluetoe::requires_encryption,\n        service_uuid_b,\n        char_1\n    >;\n\n    using server = bluetoe::server<\n        bluetoe::no_encryption_required,\n        service_1,\n        service_2\n    >;\n\n    BOOST_CHECK( bluetoe::details::requires_encryption_support_t< server >::value );\n    BOOST_CHECK(( !bluetoe::details::characteristic_requires_encryption< char_1, service_1, server >::value ));\n    BOOST_CHECK(( bluetoe::details::characteristic_requires_encryption< char_1, service_2, server >::value ));\n}\n\nBOOST_AUTO_TEST_CASE( default_requires_but_services_do_not )\n{\n    using service_1 = bluetoe::service<\n        bluetoe::no_encryption_required,\n        service_uuid_a,\n        char_1\n    >;\n\n    using service_2 = bluetoe::service<\n        bluetoe::no_encryption_required,\n        service_uuid_b,\n        char_1\n    >;\n\n    using server = bluetoe::server<\n        bluetoe::requires_encryption,\n        service_1,\n        service_2\n    >;\n\n    BOOST_CHECK( !bluetoe::details::requires_encryption_support_t< server >::value );\n    BOOST_CHECK(( !bluetoe::details::characteristic_requires_encryption< char_1, service_1, server >::value ));\n    BOOST_CHECK(( !bluetoe::details::characteristic_requires_encryption< char_1, service_2, server >::value ));\n}\n\nBOOST_AUTO_TEST_CASE( one_services_requires_encryption )\n{\n    using service_1 = bluetoe::service<\n        service_uuid_a,\n        char_1\n    >;\n\n    using service_2 = bluetoe::service<\n        bluetoe::requires_encryption,\n        service_uuid_b,\n        char_1\n    >;\n\n    using server = bluetoe::server<\n        service_1,\n        service_2\n    >;\n\n    BOOST_CHECK( bluetoe::details::requires_encryption_support_t< server >::value );\n    BOOST_CHECK(( !bluetoe::details::characteristic_requires_encryption< char_1, service_1, server >::value ));\n    BOOST_CHECK(( bluetoe::details::characteristic_requires_encryption< char_1, service_2, server >::value ));\n}\n\nBOOST_AUTO_TEST_CASE( no_encryption_as_default_but_one_char_requires_encryption )\n{\n    using service_1 = bluetoe::service<\n        service_uuid_a,\n        char_1\n    >;\n\n    using char_req = bluetoe::characteristic<\n        bluetoe::bind_characteristic_value< decltype( dummy_val ), &dummy_val >,\n        char_uuid,\n        bluetoe::requires_encryption\n    >;\n\n    using service_2 = bluetoe::service<\n        service_uuid_b,\n        char_req\n    >;\n\n    using server = bluetoe::server<\n        bluetoe::no_encryption_required,\n        service_1,\n        service_2\n    >;\n\n    BOOST_CHECK( bluetoe::details::requires_encryption_support_t< server >::value );\n    BOOST_CHECK(( !bluetoe::details::characteristic_requires_encryption< char_1, service_1, server >::value ));\n    BOOST_CHECK(( bluetoe::details::characteristic_requires_encryption< char_req, service_2, server >::value ));\n}\n\nBOOST_AUTO_TEST_CASE( service_requires_encryption_by_default_but_characteristic )\n{\n    using service_1 = bluetoe::service<\n        service_uuid_a,\n        char_1\n    >;\n\n    using char_no_enc = bluetoe::characteristic<\n        bluetoe::bind_characteristic_value< decltype( dummy_val ), &dummy_val >,\n        char_uuid,\n        bluetoe::no_encryption_required\n    >;\n\n    using service_2 = bluetoe::service<\n        bluetoe::requires_encryption,\n        service_uuid_b,\n        char_no_enc\n    >;\n\n    using server = bluetoe::server<\n        service_1,\n        service_2\n    >;\n\n    BOOST_CHECK( !bluetoe::details::requires_encryption_support_t< server >::value );\n    BOOST_CHECK(( !bluetoe::details::characteristic_requires_encryption< char_1, service_1, server >::value ));\n    BOOST_CHECK(( !bluetoe::details::characteristic_requires_encryption< char_no_enc, service_2, server >::value ));\n}\n\nBOOST_AUTO_TEST_CASE( server_may_require_encryption )\n{\n    using service = bluetoe::service<\n        service_uuid,\n        char_1\n    >;\n\n    using server = bluetoe::server<\n        bluetoe::may_require_encryption,\n        service\n    >;\n\n    BOOST_CHECK( bluetoe::details::requires_encryption_support_t< server >::value );\n    BOOST_CHECK(( !bluetoe::details::characteristic_requires_encryption< char_1, service, server >::value ));\n}\n\nBOOST_AUTO_TEST_CASE( service_may_require_encryption )\n{\n    using service = bluetoe::service<\n        bluetoe::may_require_encryption,\n        service_uuid,\n        char_1\n    >;\n\n    using server = bluetoe::server<\n        bluetoe::no_encryption_required,\n        service\n    >;\n\n    BOOST_CHECK( bluetoe::details::requires_encryption_support_t< server >::value );\n    BOOST_CHECK(( !bluetoe::details::characteristic_requires_encryption< char_1, service, server >::value ));\n}\n\nBOOST_AUTO_TEST_CASE( characteristic_may_require_encryption )\n{\n    using char_1 = bluetoe::characteristic<\n        bluetoe::bind_characteristic_value< decltype( dummy_val ), &dummy_val >,\n        char_uuid,\n        bluetoe::may_require_encryption\n    >;\n\n    using service = bluetoe::service<\n        bluetoe::no_encryption_required,\n        service_uuid,\n        char_1\n    >;\n\n    using server = bluetoe::server<\n        bluetoe::no_encryption_required,\n        service\n    >;\n\n    BOOST_CHECK( bluetoe::details::requires_encryption_support_t< server >::value );\n    BOOST_CHECK(( !bluetoe::details::characteristic_requires_encryption< char_1, service, server >::value ));\n}\n"
  },
  {
    "path": "tests/filter_tests.cpp",
    "content": "#include <bluetoe/filter.hpp>\n#include <bluetoe/attribute.hpp>\n#include <bluetoe/uuid.hpp>\n\n#define BOOST_TEST_MODULE\n#include <boost/test/included/unit_test.hpp>\n\nnamespace blued = bluetoe::details;\n\nnamespace {\n    template < class UUID >\n    blued::uuid_filter fixture()\n    {\n        return blued::uuid_filter( &UUID::bytes[ 0 ], UUID::is_128bit );\n    }\n\n    typedef bluetoe::details::uuid< 0x1, 0x2, 0x3, 0x4, 0x5 > big_uuid;\n\n    blued::attribute_access_result equal_to_big_uuid( blued::attribute_access_arguments& args, std::size_t )\n    {\n        if ( args.type == blued::attribute_access_type::compare_128bit_uuid )\n        {\n            assert( args.buffer_size == 16 );\n\n            if ( std::equal( std::begin( big_uuid::bytes ), std::end( big_uuid::bytes ), args.buffer ) )\n                return blued::attribute_access_result::uuid_equal;\n        }\n\n        return blued::attribute_access_result::read_not_permitted;\n    }\n\n}\n\nBOOST_AUTO_TEST_CASE( fitting_16bit )\n{\n    const auto             filter     = fixture< bluetoe::details::uuid16< 0x1234 > >();\n    const blued::attribute attribute  = { 0x1234, nullptr };\n\n    BOOST_CHECK( filter( 1,    attribute ) );\n    BOOST_CHECK( filter( 4711, attribute ) );\n}\n\nBOOST_AUTO_TEST_CASE( not_fitting_16bit )\n{\n    const auto             filter     = fixture< bluetoe::details::uuid16< 0x1234 > >();\n    const blued::attribute attribute  = { 0x4711, nullptr };\n\n    BOOST_CHECK( !filter( 1,    attribute ) );\n    BOOST_CHECK( !filter( 4711, attribute ) );\n}\n\nBOOST_AUTO_TEST_CASE( fitting_16bit_compaired_with_bluetooth_base_uuid )\n{\n    const auto             filter     = fixture< blued::bluetooth_base_uuid::from_16bit< 0x1234 > >();\n    const blued::attribute attribute  = { 0x1234, nullptr };\n\n    BOOST_CHECK( filter( 1,    attribute ) );\n    BOOST_CHECK( filter( 4711, attribute ) );\n}\n\nBOOST_AUTO_TEST_CASE( not_fitting_16bit_compaired_with_bluetooth_base_uuid )\n{\n    const auto             filter     = fixture< blued::bluetooth_base_uuid::from_16bit< 0x1234 > >();\n    const blued::attribute attribute  = { 0x4711, nullptr };\n\n    BOOST_CHECK( !filter( 1,    attribute ) );\n    BOOST_CHECK( !filter( 4711, attribute ) );\n}\n\nBOOST_AUTO_TEST_CASE( fitting_128bit )\n{\n    const auto             filter     = fixture< bluetoe::details::uuid< 0x1, 0x2, 0x3, 0x4, 0x5 > >();\n    const blued::attribute attribute  = { bits( blued::gatt_uuids::internal_128bit_uuid ), equal_to_big_uuid };\n\n    BOOST_CHECK( filter( 1,    attribute ) );\n    BOOST_CHECK( filter( 4711, attribute ) );\n}\n\nBOOST_AUTO_TEST_CASE( not_fitting_128bit )\n{\n    const auto             filter     = fixture< bluetoe::details::uuid< 0x1, 0x2, 0x3, 0x4, 0x6 > >();\n    const blued::attribute attribute  = { bits( blued::gatt_uuids::internal_128bit_uuid ), equal_to_big_uuid };\n\n    BOOST_CHECK( !filter( 1,    attribute ) );\n    BOOST_CHECK( !filter( 4711, attribute ) );\n}\n\nBOOST_AUTO_TEST_CASE( compare_16bit_with_128bit )\n{\n    const auto             filter     = fixture< bluetoe::details::uuid16< 0x1234 > >();\n    const blued::attribute attribute  = { bits( blued::gatt_uuids::internal_128bit_uuid ), equal_to_big_uuid };\n\n    BOOST_CHECK( !filter( 1,    attribute ) );\n    BOOST_CHECK( !filter( 4711, attribute ) );\n}\n\nBOOST_AUTO_TEST_CASE( compare_128bit_with_16bit )\n{\n    const auto             filter     = fixture< bluetoe::details::uuid< 0x1, 0x2, 0x3, 0x4, 0x6 > >();\n    const blued::attribute attribute  = { 0x4711, nullptr };\n\n    BOOST_CHECK( !filter( 1,    attribute ) );\n    BOOST_CHECK( !filter( 4711, attribute ) );\n}\n\nBOOST_AUTO_TEST_CASE( matching_uuid16_filter )\n{\n    blued::uuid16_filter< blued::uuid16< 0x2800 > > filter;\n    const blued::attribute attribute  = { 0x2800, nullptr };\n\n    BOOST_CHECK( filter( 1,    attribute ) );\n    BOOST_CHECK( filter( 4711, attribute ) );\n}\n\nBOOST_AUTO_TEST_CASE( nomatching_uuid16_filter )\n{\n    blued::uuid16_filter< blued::uuid16< 0x2800 > > filter;\n    const blued::attribute attribute  = { 0x2801, nullptr };\n\n    BOOST_CHECK( !filter( 1,    attribute ) );\n    BOOST_CHECK( !filter( 4711, attribute ) );\n}\n"
  },
  {
    "path": "tests/gap_service_tests.cpp",
    "content": "#include <bluetoe/gap_service.hpp>\n#include <bluetoe/server.hpp>\n\n#define BOOST_TEST_MODULE\n#include <boost/test/included/unit_test.hpp>\n\n#include \"test_servers.hpp\"\n\n\nstd::uint16_t nupsy = 0x0104;\nstatic constexpr char nupsy_name[] = \"Nupsy-Server\";\n\ntypedef bluetoe::server<\n    bluetoe::server_name< nupsy_name >,\n    bluetoe::service<\n        bluetoe::service_uuid< 0x8C8B4094, 0x0DE2, 0x499F, 0xA28A, 0x4EED5BC73CA9 >,\n        bluetoe::characteristic<\n            bluetoe::characteristic_uuid< 0x8C8B4094, 0x0DE2, 0x499F, 0xA28A, 0x4EED5BC73CAA >,\n            bluetoe::bind_characteristic_value< decltype( nupsy ), &nupsy >,\n            bluetoe::no_write_access\n        >\n    >\n> nupsy_service;\n\n// service is discoverable and contains at least two characteristics\nBOOST_FIXTURE_TEST_CASE( service_is_discoverable_by_default, test::request_with_reponse< nupsy_service > )\n{\n    // Find By Type Value Request, 1, 0xffff, <<primary service>>, <<gap service>>\n    l2cap_input( { 0x06, 0x01, 0x00, 0xff, 0xff, 0x00, 0x28, 0x00, 0x18 } );\n    expected_result( {\n        0x07,\n        0x04, 0x00, 0x08, 0x00\n    } );\n}\n\ntypedef bluetoe::server<\n    bluetoe::service<\n        bluetoe::service_uuid< 0x8C8B4094, 0x0DE2, 0x499F, 0xA28A, 0x4EED5BC73CA9 >,\n        bluetoe::characteristic<\n            bluetoe::characteristic_uuid< 0x8C8B4094, 0x0DE2, 0x499F, 0xA28A, 0x4EED5BC73CAA >,\n            bluetoe::bind_characteristic_value< decltype( nupsy ), &nupsy >,\n            bluetoe::no_write_access\n        >\n    >,\n    bluetoe::no_gap_service_for_gatt_servers\n> without_gap_service_service;\n\nBOOST_FIXTURE_TEST_CASE( no_service_no_cookies, test::request_with_reponse< without_gap_service_service > )\n{\n    // Find By Type Value Request, 1, 0xffff, <<primary service>>, <<gap service>>\n    check_error_response(\n        { 0x06, 0x01, 0x00, 0xff, 0xff, 0x00, 0x28, 0x11, 0x47 },\n        0x06, 0x0001, 0x0a\n    );\n}\n\nBOOST_FIXTURE_TEST_CASE( appearance_is_mandatory, test::request_with_reponse< nupsy_service > )\n{\n    // Read by Type Request, 0x0001, 0xffff, 0x2A01\n    l2cap_input( { 0x08, 0x01, 0x00, 0xff, 0xff, 0x01, 0x2A } );\n    expected_result( {\n        0x09,\n        0x04, 0x08, 0x00, 0x00, 0x00\n    } );\n}\n\nBOOST_FIXTURE_TEST_CASE( no_service_no_appearance, test::request_with_reponse< without_gap_service_service > )\n{\n    // Read by Type Request, 0x0001, 0xffff, 0x2A01\n    check_error_response(\n        { 0x08, 0x01, 0x00, 0xff, 0xff, 0x01, 0x2A },\n        0x08, 0x0001, 0x0a\n    );\n}\n\ntypedef bluetoe::server<\n    bluetoe::service<\n        bluetoe::service_uuid< 0x8C8B4094, 0x0DE2, 0x499F, 0xA28A, 0x4EED5BC73CA9 >,\n        bluetoe::characteristic<\n            bluetoe::characteristic_uuid< 0x8C8B4094, 0x0DE2, 0x499F, 0xA28A, 0x4EED5BC73CAA >,\n            bluetoe::bind_characteristic_value< decltype( nupsy ), &nupsy >,\n            bluetoe::no_write_access\n        >\n    >,\n    bluetoe::appearance::location_and_navigation_display_device\n> location_and_navigation_display_device_server;\n\nBOOST_FIXTURE_TEST_CASE( configured_appearance_is_used, test::request_with_reponse< location_and_navigation_display_device_server > )\n{\n    // Read by Type Request, 0x0001, 0xffff, 0x2A01\n    l2cap_input( { 0x08, 0x01, 0x00, 0xff, 0xff, 0x01, 0x2A } );\n    expected_result( {\n        0x09,\n        0x04, 0x08, 0x00, 0x42, 0x14\n    } );\n}\n\nBOOST_FIXTURE_TEST_CASE( device_name_is_mandatory, test::request_with_reponse< nupsy_service > )\n{\n    // Read by Type Request, 0x0001, 0xffff, 0x2A00\n    l2cap_input( { 0x08, 0x01, 0x00, 0xff, 0xff, 0x00, 0x2A } );\n    expected_result( {\n        0x09,\n        0x0e, 0x06, 0x00, // length + handle\n        // \"Nupsy-Server\"\n        'N', 'u', 'p', 's', 'y', '-', 'S', 'e', 'r', 'v', 'e', 'r'\n    } );\n}\n\ntypedef bluetoe::server<\n    bluetoe::service<\n        bluetoe::service_uuid< 0x8C8B4094, 0x0DE2, 0x499F, 0xA28A, 0x4EED5BC73CA9 >,\n        bluetoe::characteristic<\n            bluetoe::characteristic_uuid< 0x8C8B4094, 0x0DE2, 0x499F, 0xA28A, 0x4EED5BC73CAA >,\n            bluetoe::bind_characteristic_value< decltype( nupsy ), &nupsy >,\n            bluetoe::no_write_access\n        >\n    >\n> no_name_service;\n\nBOOST_FIXTURE_TEST_CASE( default_name, test::request_with_reponse< no_name_service > )\n{\n    // Read by Type Request, 0x0001, 0xffff, 0x2A00\n    l2cap_input( { 0x08, 0x01, 0x00, 0xff, 0xff, 0x00, 0x2A } );\n    expected_result( {\n        0x09,\n        0x10, 0x06, 0x00, // length + handle\n        // \"Bluetoe-Server\"\n        'B', 'l', 'u', 'e', 't', 'o', 'e', '-', 'S', 'e', 'r', 'v', 'e', 'r'\n    } );\n}\n"
  },
  {
    "path": "tests/hci/CMakeLists.txt",
    "content": "add_and_register_test(hci_advertising_tests)\ntarget_link_libraries(hci_advertising_tests PRIVATE bluetoe::hci)\n"
  },
  {
    "path": "tests/hci/hci_advertising_tests.cpp",
    "content": "#define BOOST_TEST_MODULE\n#include <boost/test/included/unit_test.hpp>\n\n#include <bluetoe/server.hpp>\n#include <bluetoe/service.hpp>\n#include <bluetoe/characteristic.hpp>\n#include <bluetoe/link_layer.hpp>\n#include \"transport.hpp\"\n\nstd::uint16_t value = 0x0815;\n\nusing simple_gatt_server = bluetoe::server<\n    bluetoe::service<\n        bluetoe::service_uuid16< 0x4766 >,\n        bluetoe::characteristic<\n            bluetoe::characteristic_uuid16< 0x2021 >,\n            bluetoe::bind_characteristic_value< std::uint16_t, &value >\n        >\n    >\n>;\n\nusing link_layer = bluetoe::hci::link_layer< simple_gatt_server, test::transport >;\n\nBOOST_FIXTURE_TEST_CASE( starts_advertising, link_layer )\n{\n\n}"
  },
  {
    "path": "tests/hci/transport.hpp",
    "content": "#ifndef TESTS_HCI_TRANSPORT_HPP\n#define TESTS_HCI_TRANSPORT_HPP\n\nnamespace test\n{\n    template < typename LinkLayer >\n    class transport\n    {\n\n    };\n}\n\n#endif\n"
  },
  {
    "path": "tests/l2cap_tests.cpp",
    "content": "#include <bluetoe/l2cap.hpp>\n\n#define BOOST_TEST_MODULE\n#include <boost/test/included/unit_test.hpp>\n\nclass base_data\n{\npublic:\n    base_data() : base( 0 ) {}\n    int base;\n};\n\nclass channel_a\n{\npublic:\n    static constexpr std::uint16_t channel_id = 42;\n    static constexpr std::size_t   minimum_channel_mtu_size = 19;\n    static constexpr std::size_t   maximum_channel_mtu_size = 44;\n\n    template < typename ConnectionData >\n    void l2cap_input( const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size, ConnectionData& connection )\n    {\n        BOOST_REQUIRE( in_size >= 1 );\n        BOOST_REQUIRE( out_size >= minimum_channel_mtu_size );\n\n        output[ 0 ] = *input;\n        output[ 1 ] = 'a';\n        out_size = 2;\n\n        connection.a = 'A';\n    }\n\n    template < typename ConnectionData >\n    void l2cap_output( std::uint8_t* output, std::size_t& out_size, ConnectionData& connection )\n    {\n        if ( connection.a != 0 )\n        {\n            output[ 0 ] = static_cast< std::uint8_t >( connection.a );\n            output[ 1 ] = static_cast< std::uint8_t >( connection.b );\n            out_size = 2;\n\n            connection.a = 0;\n        }\n        else\n        {\n            out_size = 0;\n        }\n    }\n\n    template < class Next >\n    struct private_data : Next {\n        private_data() : a( 0 )\n        {\n        }\n\n        int a;\n    };\n\n    template < class PreviousData >\n    struct channel_data_t : private_data< PreviousData > {};\n};\n\nclass channel_b\n{\npublic:\n    static constexpr std::uint16_t channel_id = 43;\n    static constexpr std::size_t   minimum_channel_mtu_size = 22;\n    static constexpr std::size_t   maximum_channel_mtu_size = 30;\n\n    template < typename ConnectionData >\n    void l2cap_input( const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size, ConnectionData& connection )\n    {\n        BOOST_REQUIRE( in_size >= 1 );\n        BOOST_REQUIRE( out_size >= minimum_channel_mtu_size );\n\n        output[ 0 ] = *input;\n        output[ 1 ] = 'b';\n        out_size = 2;\n\n        connection.b = 'B';\n    }\n\n    template < typename ConnectionData >\n    void l2cap_output( std::uint8_t* output, std::size_t& out_size, ConnectionData& connection )\n    {\n        if ( connection.b != 0 )\n        {\n            output[ 0 ] = static_cast< std::uint8_t >( connection.b );\n            output[ 1 ] = static_cast< std::uint8_t >( connection.a );\n            out_size = 2;\n\n            connection.b = 0;\n        }\n        else\n        {\n            out_size = 0;\n        }\n    }\n\n    template < class Next >\n    struct private_data {\n        private_data() : b( 0 )\n        {\n        }\n\n        int b;\n    };\n\n    template < class PreviousData >\n    struct channel_data_t : private_data< PreviousData > {};\n};\n\nclass link_layer : public bluetoe::details::l2cap< link_layer, base_data, channel_a, channel_b >\n{\npublic:\n    link_layer()\n        : current_buffer_used_( 0 )\n    {\n    }\n\n    using bluetoe::details::l2cap< link_layer, base_data, channel_a, channel_b >::handle_l2cap_input;\n\n    bool handle_l2cap_input( std::uint16_t channel, std::initializer_list< std::uint8_t > input )\n    {\n        std::vector< std::uint8_t > pdu = {\n            low( input.size() ), high( input.size() ),\n            low( channel ), high( channel )\n        };\n\n        pdu.insert( pdu.end(), input.begin(), input.end() );\n\n        return bluetoe::details::l2cap< link_layer, base_data, channel_a, channel_b >::handle_l2cap_input(\n            pdu.data(), pdu.size(), connection_data_ );\n    }\n\n    void add_buffer( std::size_t size )\n    {\n        BOOST_REQUIRE( current_buffer_used_ <= current_buffer_used_ + size );\n\n        buffers_.push_back( { size, &overall_buffer_[ current_buffer_used_ ] } );\n        current_buffer_used_ += size;\n    }\n\n    /*\n     * Interface to the l2cap\n     */\n    std::pair< std::size_t, std::uint8_t* > allocate_l2cap_output_buffer( std::size_t size )\n    {\n        if ( buffers_.empty() )\n            return { 0, nullptr };\n\n        const auto buf = buffers_.front();\n\n        if ( buf.first < size )\n            return { 0, nullptr };\n\n        buffers_.erase( buffers_.begin() );\n\n        return buf;\n    }\n\n    void commit_l2cap_output_buffer( std::pair< std::size_t, std::uint8_t* > buffer )\n    {\n        output_.push_back( std::vector< std::uint8_t >{ buffer.second, buffer.second + buffer.first } );\n    }\n\n    void check_next_output( std::initializer_list< std::uint8_t > expected )\n    {\n        std::vector< std::uint8_t > next;\n\n        if ( !output_.empty() )\n        {\n            next = output_.front();\n            output_.erase( output_.begin() );\n        }\n\n        BOOST_CHECK_EQUAL_COLLECTIONS(\n            expected.begin(), expected.end(),\n            next.begin(), next.end() );\n    }\n\n    connection_data_t connection_data_;\n\nprivate:\n    static std::uint8_t low( std::uint16_t b )\n    {\n        return b & 0xff;\n    }\n\n    static std::uint8_t high( std::uint16_t b )\n    {\n        return b >> 8;\n    }\n\n    std::uint8_t overall_buffer_[ 2048 ];\n    std::size_t  current_buffer_used_;\n\n    std::vector< std::pair< std::size_t, std::uint8_t*  > > buffers_;\n    std::vector< std::vector< std::uint8_t > > output_;\n};\n\nstruct link_layer_with_free_buffer : link_layer\n{\n    link_layer_with_free_buffer()\n    {\n        add_buffer( 44u );\n    }\n};\n\nBOOST_FIXTURE_TEST_SUITE( invalid_input, link_layer_with_free_buffer )\n\nBOOST_AUTO_TEST_CASE( invalid_channel )\n{\n    // invalid channel, id will be ignored\n    BOOST_CHECK( handle_l2cap_input( 4711, { 0x01, 0x02 } ) );\n    check_next_output( {} );\n}\n\nBOOST_AUTO_TEST_CASE( input_smaller_than_header )\n{\n    const std::initializer_list< std::uint8_t > input = { 0x01, 0x02, 42 };\n\n    BOOST_CHECK( handle_l2cap_input( input.begin(), 3, connection_data_ ) );\n    check_next_output( {} );\n}\n\nBOOST_AUTO_TEST_CASE( inconsistent_length_to_small )\n{\n    const std::initializer_list< std::uint8_t > input = { 0x01, 0x00, 42, 0x00 };\n\n    BOOST_CHECK( handle_l2cap_input( input.begin(), 4, connection_data_ ) );\n    check_next_output( {} );\n}\n\nBOOST_AUTO_TEST_CASE( inconsistent_length_to_large )\n{\n    const std::initializer_list< std::uint8_t > input = { 0x01, 0x00, 42, 0x00, 0x01, 0x02 };\n\n    BOOST_CHECK( handle_l2cap_input( input.begin(), 6, connection_data_ ) );\n    check_next_output( {} );\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_FIXTURE_TEST_SUITE( input_tests, link_layer )\n\nBOOST_AUTO_TEST_CASE( calculated_min_mtu )\n{\n    BOOST_TEST( std::size_t{ minimum_mtu_size } == 22u );\n}\n\nBOOST_AUTO_TEST_CASE( calculated_max_mtu )\n{\n    BOOST_TEST( std::size_t{ maximum_mtu_size } == 44u );\n}\n\nBOOST_AUTO_TEST_CASE( if_minumum_mtu_size_can_not_be_allocated_pdu_will_not_be_handled )\n{\n    add_buffer( 43u );\n    BOOST_TEST( handle_l2cap_input( 42, { 0x01, 0x02 } ) == false );\n}\n\nBOOST_AUTO_TEST_CASE( correct_frameing )\n{\n    add_buffer( 44u );\n    BOOST_TEST( handle_l2cap_input( 42, { 0x01 } ) );\n\n    check_next_output( { 0x02, 0x00, 42, 0x00, 0x01, 'a' } );\n}\n\nBOOST_AUTO_TEST_CASE( private_data_modifiable_a )\n{\n    add_buffer( 44u );\n    BOOST_TEST( handle_l2cap_input( 42, { 0x01 } ) );\n\n    BOOST_TEST( connection_data_.a == 'A' );\n    BOOST_TEST( connection_data_.b == 0 );\n}\n\nBOOST_AUTO_TEST_CASE( private_data_modifiable_b )\n{\n    add_buffer( 44u );\n    BOOST_TEST( handle_l2cap_input( 43, { 0x01 } ) );\n\n    BOOST_TEST( connection_data_.a == 0 );\n    BOOST_TEST( connection_data_.b == 'B' );\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_FIXTURE_TEST_SUITE( output_buffer, link_layer_with_free_buffer )\n\nBOOST_AUTO_TEST_CASE( not_enough_buffer_for_outgoing_pdu )\n{\n    // consume the first buffer, by requesting a response\n    BOOST_TEST( handle_l2cap_input( 42, { 0x01 } ) );\n    check_next_output( { 0x02, 0x00, 42, 0x00, 0x01, 'a' } );\n\n    transmit_pending_l2cap_output( connection_data_ );\n    check_next_output( {} );\n}\n\nBOOST_AUTO_TEST_CASE( read_pending_from_channel_a )\n{\n    BOOST_TEST( handle_l2cap_input( 42, { 0x02 } ) );\n    check_next_output( { 0x02, 0x00, 42, 0x00, 0x02, 'a' } );\n\n    add_buffer( 44u );\n    transmit_pending_l2cap_output( connection_data_ );\n    check_next_output( { 0x02, 0x00, 42, 0x00, 'A', 0x00 } );\n}\n\nBOOST_AUTO_TEST_CASE( read_pending_from_channel_b )\n{\n    BOOST_TEST( handle_l2cap_input( 43, { 0x03 } ) );\n    check_next_output( { 0x02, 0x00, 43, 0x00, 0x03, 'b' } );\n\n    add_buffer( 44u );\n    transmit_pending_l2cap_output( connection_data_ );\n    check_next_output( { 0x02, 0x00, 43, 0x00, 'B', 0x00 } );\n}\n\nBOOST_AUTO_TEST_CASE( read_pending_from_multiple_channels )\n{\n    BOOST_TEST( handle_l2cap_input( 42, { 0x02 } ) );\n    check_next_output( { 0x02, 0x00, 42, 0x00, 0x02, 'a' } );\n\n    add_buffer( 44u );\n    BOOST_TEST( handle_l2cap_input( 43, { 0x03 } ) );\n    check_next_output( { 0x02, 0x00, 43, 0x00, 0x03, 'b' } );\n\n    add_buffer( 44u );\n    add_buffer( 44u );\n    transmit_pending_l2cap_output( connection_data_ );\n    check_next_output( { 0x02, 0x00, 42, 0x00, 'A', 'B' } );\n    check_next_output( { 0x02, 0x00, 43, 0x00, 'B', 0x00 } );\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "tests/link_layer/CMakeLists.txt",
    "content": "function (add_and_register_ll_test target)\n    add_and_register_test(${target})\n    target_link_libraries(${target} PRIVATE bluetoe::link_layer)\nendfunction()\n\nadd_and_register_ll_test(ll_advertising_tests)\nadd_and_register_ll_test(address_tests)\nadd_and_register_ll_test(channel_map_tests)\nadd_and_register_ll_test(delta_time_tests)\nadd_and_register_ll_test(ll_data_pdu_buffer_tests)\nadd_and_register_ll_test(ll_connection_tests)\nadd_and_register_ll_test(ll_connecting_tests)\nadd_and_register_ll_test(ll_control_tests)\nadd_and_register_ll_test(ll_data_tests)\nadd_and_register_ll_test(ring_buffer_tests)\nadd_and_register_ll_test(connection_callbacks_tests)\nadd_and_register_ll_test(signaling_channel_tests)\nadd_and_register_ll_test(white_list_tests)\nadd_and_register_ll_test(connection_parameter_update_procedure_tests)\nadd_and_register_ll_test(test_radio_tests)\nadd_and_register_ll_test(advertiser_tests)\nadd_and_register_ll_test(ll_encryption_tests)\nadd_and_register_ll_test(ll_l2cap_sdu_buffer_tests)\nadd_and_register_ll_test(peripheral_latency_tests)\nadd_and_register_ll_test(ll_peripheral_latency_tests)\nadd_and_register_ll_test(ll_phy_update_tests)\nadd_and_register_ll_test(connection_event_callback_tests)\nadd_and_register_ll_test(ll_notification_tests)\nadd_and_register_ll_test(ll_remote_request_tests)"
  },
  {
    "path": "tests/link_layer/address_tests.cpp",
    "content": "#include <bluetoe/address.hpp>\n\n#define BOOST_TEST_MODULE\n#include <boost/test/included/unit_test.hpp>\n\nBOOST_FIXTURE_TEST_CASE( is_default_constructable, bluetoe::link_layer::address )\n{\n    BOOST_CHECK_EQUAL( *this,  bluetoe::link_layer::address( { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } ) );\n}\n\nBOOST_AUTO_TEST_CASE( is_initalizable_by_list )\n{\n    bluetoe::link_layer::address a( { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 } );\n}\n\nBOOST_AUTO_TEST_CASE( is_initalizable_by_array )\n{\n    static const std::uint8_t arr[ 6 ] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 };\n\n    BOOST_CHECK_EQUAL( bluetoe::link_layer::address( &arr[ 0 ] ), bluetoe::link_layer::address(  { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 } ) );\n}\n\nBOOST_AUTO_TEST_CASE( outputable )\n{\n    boost::test_tools::output_test_stream output;\n\n    output << bluetoe::link_layer::address( { 0x01, 0xFF, 0x10, 0x04, 0x55, 0xAb } );\n\n    BOOST_CHECK( output.is_equal( \"01:ff:10:04:55:ab\" ) );\n}\n\nBOOST_AUTO_TEST_CASE( is_equal_compareble )\n{\n    const bluetoe::link_layer::address a( { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 } );\n    const bluetoe::link_layer::address b( { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 } );\n    const bluetoe::link_layer::address c( { 0x01, 0x02, 0x03, 0x04, 0x05, 0x07 } );\n    const bluetoe::link_layer::address d( { 0x10, 0x02, 0x03, 0x04, 0x05, 0x06 } );\n\n    BOOST_CHECK_EQUAL( a, a );\n    BOOST_CHECK_EQUAL( a, b );\n    BOOST_CHECK_EQUAL( b, a );\n    BOOST_CHECK( !( a == c ) );\n    BOOST_CHECK( !( a == d ) );\n}\n\nBOOST_AUTO_TEST_CASE( is_unequal_compareble )\n{\n    const bluetoe::link_layer::address a( { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 } );\n    const bluetoe::link_layer::address b( { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 } );\n    const bluetoe::link_layer::address c( { 0x01, 0x02, 0x03, 0x04, 0x05, 0x07 } );\n    const bluetoe::link_layer::address d( { 0x10, 0x02, 0x03, 0x04, 0x05, 0x06 } );\n\n    BOOST_CHECK( !( a != a ) );\n    BOOST_CHECK( !( a != b ) );\n    BOOST_CHECK_NE( a, c );\n    BOOST_CHECK_NE( a, d );\n}\n\nBOOST_AUTO_TEST_CASE( gives_access_to_the_msb )\n{\n    BOOST_CHECK_EQUAL( 0x45, bluetoe::link_layer::address( { 0x00, 0x00, 0x00, 0x00, 0x00, 0x45 } ).msb() );\n}\n\nBOOST_AUTO_TEST_CASE( implements_iterator_access )\n{\n    bluetoe::link_layer::address a( { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 } );\n    const std::uint8_t exepect_values[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 };\n\n    BOOST_CHECK_EQUAL_COLLECTIONS( a.begin(), a.end(), std::begin( exepect_values ), std::end( exepect_values ) );\n}\n\nBOOST_AUTO_TEST_CASE( a_default_contructed_public_address_is_public )\n{\n    bluetoe::link_layer::public_device_address addr;\n    BOOST_CHECK( addr.is_public() );\n    BOOST_CHECK( !addr.is_random() );\n}\n\nBOOST_AUTO_TEST_CASE( a_public_address_is_public )\n{\n    bluetoe::link_layer::public_device_address addr( { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 } );\n    BOOST_CHECK( addr.is_public() );\n    BOOST_CHECK( !addr.is_random() );\n}\n\nBOOST_AUTO_TEST_CASE( a_public_address_is_an_address )\n{\n    bluetoe::link_layer::public_device_address addr( { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 } );\n\n    BOOST_CHECK_EQUAL( addr, bluetoe::link_layer::address( { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 } ) );\n}\n\nBOOST_AUTO_TEST_CASE( a_default_contructed_random_address_is_random )\n{\n    bluetoe::link_layer::random_device_address addr;\n    BOOST_CHECK( !addr.is_public() );\n    BOOST_CHECK( addr.is_random() );\n}\n\nBOOST_AUTO_TEST_CASE( a_random_address_is_random )\n{\n    bluetoe::link_layer::random_device_address addr( { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 } );\n    BOOST_CHECK( !addr.is_public() );\n    BOOST_CHECK( addr.is_random() );\n}\n\nBOOST_AUTO_TEST_CASE( a_random_address_is_an_address )\n{\n    bluetoe::link_layer::random_device_address addr( { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 } );\n\n    BOOST_CHECK_EQUAL( addr, bluetoe::link_layer::address( { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 } ) );\n}\n\nBOOST_AUTO_TEST_CASE( random_and_public_address_are_not_equal )\n{\n    bluetoe::link_layer::random_device_address addr1( { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 } );\n    bluetoe::link_layer::public_device_address addr2( { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 } );\n\n    BOOST_CHECK_NE( addr1, addr2 );\n    BOOST_CHECK( !( addr1 == addr2 ) );\n}\n\nBOOST_AUTO_TEST_CASE( random_addresses_are_equal )\n{\n    bluetoe::link_layer::random_device_address addr1( { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 } );\n    bluetoe::link_layer::random_device_address addr2( { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 } );\n\n    BOOST_CHECK_EQUAL( addr1, addr2 );\n    BOOST_CHECK( !( addr1 != addr2 ) );\n}\n\nBOOST_AUTO_TEST_CASE( public_addresses_are_equal )\n{\n    bluetoe::link_layer::public_device_address addr1( { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 } );\n    bluetoe::link_layer::public_device_address addr2( { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 } );\n\n    BOOST_CHECK_EQUAL( addr1, addr2 );\n    BOOST_CHECK( !( addr1 != addr2 ) );\n}\n"
  },
  {
    "path": "tests/link_layer/advertiser_tests.cpp",
    "content": "#include \"buffer_io.hpp\"\n\n#define BOOST_TEST_MODULE\n#include <boost/test/included/unit_test.hpp>\n#include <boost/mpl/list.hpp>\n\n#include <bluetoe/advertising.hpp>\n#include <bluetoe/white_list.hpp>\n\n#include \"test_radio.hpp\"\n\ntemplate < bool Connect, bool Respond >\nstruct link_layer_base\n{\n    link_layer_base()\n        : advertisment_scheduled( false )\n    {\n        std::fill( std::begin( buffer_ ), std::end( buffer_ ), 0 );\n    }\n\n    bool is_connection_request_in_filter( const bluetoe::link_layer::device_address& ) const\n    {\n        return Connect;\n    }\n\n    bool is_scan_request_in_filter( const bluetoe::link_layer::device_address& ) const\n    {\n        return Respond;\n    }\n\n    bool l2cap_adverting_data_or_scan_response_data_changed() const\n    {\n        return false;\n    }\n\n    void schedule_advertisment(\n        unsigned,\n        const bluetoe::link_layer::write_buffer&,\n        const bluetoe::link_layer::write_buffer&,\n        bluetoe::link_layer::delta_time,\n        const bluetoe::link_layer::read_buffer& )\n    {\n    }\n\n    std::size_t fill_l2cap_advertising_data( std::uint8_t*, std::size_t ) const\n    {\n        return 0;\n    }\n\n    std::size_t fill_l2cap_scan_response_data( std::uint8_t*, std::size_t ) const\n    {\n        return 0;\n    }\n\n    const bluetoe::link_layer::device_address& local_address() const\n    {\n        static const bluetoe::link_layer::random_device_address addr( { 0x47, 0x11, 0x08, 0x15, 0x0f, 0xc0 } );\n\n        return addr;\n    }\n\n    std::uint8_t* raw_pdu_buffer()\n    {\n        return buffer_;\n    }\n\n    std::uint8_t buffer_[ 1024 ];\n    bool advertisment_scheduled;\n\n    using radio_t = test::radio< 100, 100, link_layer_base< Connect, Respond > >;\n};\n\nstruct single_advertiser_without_white_list :\n    link_layer_base< true, true >,\n    bluetoe::link_layer::details::select_advertiser_implementation<\n        single_advertiser_without_white_list\n    >\n{\n};\n\nstruct multi_advertiser_without_white_list :\n    link_layer_base< true, true >,\n    bluetoe::link_layer::details::select_advertiser_implementation<\n        multi_advertiser_without_white_list,\n        bluetoe::link_layer::connectable_undirected_advertising,\n        bluetoe::link_layer::connectable_directed_advertising,\n        bluetoe::link_layer::scannable_undirected_advertising,\n        bluetoe::link_layer::non_connectable_undirected_advertising\n    >\n{\n};\n\nstruct single_advertiser_with_white_list :\n    link_layer_base< false, false >,\n    bluetoe::link_layer::details::select_advertiser_implementation<\n        single_advertiser_with_white_list\n    >\n{\n};\n\nstruct multi_advertiser_with_white_list :\n    link_layer_base< false, false >,\n    bluetoe::link_layer::details::select_advertiser_implementation<\n        multi_advertiser_with_white_list,\n        bluetoe::link_layer::connectable_undirected_advertising,\n        bluetoe::link_layer::connectable_directed_advertising,\n        bluetoe::link_layer::scannable_undirected_advertising,\n        bluetoe::link_layer::non_connectable_undirected_advertising\n    >\n{\n};\n\ntypedef boost::mpl::list<\n    single_advertiser_without_white_list,\n    multi_advertiser_without_white_list,\n    single_advertiser_with_white_list,\n    multi_advertiser_with_white_list\n> all_fixtures;\n\nBOOST_AUTO_TEST_CASE_TEMPLATE( empty_request, Advertiser, all_fixtures )\n{\n    bluetoe::link_layer::device_address remote_address;\n    Advertiser advertiser;\n    const bool result = advertiser.handle_adv_receive( bluetoe::link_layer::read_buffer{ nullptr, 0 }, remote_address );\n\n    BOOST_CHECK( !result );\n    BOOST_CHECK_EQUAL( remote_address, bluetoe::link_layer::device_address() );\n}\n\ntypedef boost::mpl::list<\n    single_advertiser_without_white_list,\n    multi_advertiser_without_white_list\n> all_without_white_list;\n\nbluetoe::link_layer::read_buffer valid_connection_request()\n{\n    // the test PDU layout has the header inverted and 2 extra octets between header and body\n    static const std::initializer_list< std::uint8_t > data = {\n        0xc5 ^ 0xff, 0x22 ^ 0xff,           // header\n        0x12, 0x34,                         // extra bytes\n        0x3c, 0x1c, 0x62, 0x92, 0xf0, 0x49, // InitA: 49:f0:92:62:1c:3c (random)\n        0x47, 0x11, 0x08, 0x15, 0x0f, 0xc0, // AdvA:  c0:0f:15:08:11:47 (random)\n        0x5a, 0xb3, 0x9a, 0xaf,             // Access Address\n        0x08, 0x81, 0xf6,                   // CRC Init\n        0x03,                               // transmit window size\n        0x18, 0x00,                         // window offset\n        0x18, 0x00,                         // interval\n        0x00, 0x00,                         // peripheral latency\n        0x80, 0x0c,                         // connection timeout\n        0xff, 0xff, 0xff, 0xff, 0x1f,       // used channel map\n        0xaa                                // hop increment and sleep clock accuracy\n    };\n\n    return bluetoe::link_layer::read_buffer{ const_cast< std::uint8_t* >( data.begin() ), data.size() };\n}\n\nstatic const bluetoe::link_layer::random_device_address remote_address( { 0x3c, 0x1c, 0x62, 0x92, 0xf0, 0x49 } );\n\nBOOST_AUTO_TEST_CASE_TEMPLATE( accept_connection_request_in_white_list, Advertiser, all_without_white_list )\n{\n    bluetoe::link_layer::device_address remote;\n    Advertiser advertiser;\n\n    const bool result = advertiser.handle_adv_receive( valid_connection_request(), remote );\n\n    BOOST_CHECK( result );\n    BOOST_CHECK_EQUAL( remote, remote_address );\n}\n\ntypedef boost::mpl::list<\n    single_advertiser_with_white_list,\n    multi_advertiser_with_white_list\n> all_with_white_list;\n\nBOOST_AUTO_TEST_CASE_TEMPLATE( no_connection_with_white_list, Advertiser, all_with_white_list )\n{\n    bluetoe::link_layer::device_address remote;\n    Advertiser advertiser;\n\n    const bool result = advertiser.handle_adv_receive( valid_connection_request(), remote );\n\n    BOOST_CHECK( !result );\n}\n"
  },
  {
    "path": "tests/link_layer/channel_map_tests.cpp",
    "content": "#include <bluetoe/channel_map.hpp>\n\n#define BOOST_TEST_MODULE\n#include <boost/test/included/unit_test.hpp>\n\nstatic constexpr std::uint8_t all_channel_map[] = { 0xff, 0xff, 0xff, 0xff, 0x1f };\nstatic constexpr std::uint8_t all_but_one_map[] = { 0xff, 0xff, 0xff, 0xff, 0xf };\n\ntemplate < unsigned Hop, const std::uint8_t*  Map >\nstruct fixture : bluetoe::link_layer::channel_map\n{\n    fixture()\n    {\n        BOOST_REQUIRE( reset( Map, Hop ) );\n    }\n};\n\n\ntemplate < unsigned Hop >\nusing all_channel = fixture< Hop, all_channel_map >;\n\ntemplate < unsigned Hop >\nusing all_but_one_channel = fixture< Hop, all_but_one_map >;\n\nusing all_channel_5 = all_channel< 5 >;\n\nBOOST_FIXTURE_TEST_CASE( all_channels_hop_5, all_channel_5 )\n{\n    BOOST_CHECK_EQUAL( data_channel( 0 ), 5u );\n    BOOST_CHECK_EQUAL( data_channel( 1 ), 10u );\n    //...\n    BOOST_CHECK_EQUAL( data_channel( 17 ), 16u );\n    //...\n    BOOST_CHECK_EQUAL( data_channel( 35 ), 32u );\n    BOOST_CHECK_EQUAL( data_channel( 36 ), 0u );\n}\n\nusing all_channel_16 = all_channel< 16 >;\n\nBOOST_FIXTURE_TEST_CASE( all_channels_hop_16, all_channel_16 )\n{\n    BOOST_CHECK_EQUAL( data_channel( 0 ), 16u );\n    BOOST_CHECK_EQUAL( data_channel( 1 ), 32u );\n    //...\n    BOOST_CHECK_EQUAL( data_channel( 11 ), 7u );\n    //...\n    BOOST_CHECK_EQUAL( data_channel( 35 ), 21u );\n    BOOST_CHECK_EQUAL( data_channel( 36 ), 0u );\n}\n\nusing all_channel_10 = all_channel< 10 >;\n\nBOOST_FIXTURE_TEST_CASE( all_channels_hop_10, all_channel_10 )\n{\n    BOOST_CHECK_EQUAL( data_channel( 0 ), 10u );\n    BOOST_CHECK_EQUAL( data_channel( 1 ), 20u );\n    // ...\n    BOOST_CHECK_EQUAL( data_channel( 7 ), 6u );\n    BOOST_CHECK_EQUAL( data_channel( 10 ), 36u );\n    // ...\n    BOOST_CHECK_EQUAL( data_channel( 35 ), unsigned{ ( 36 * 10 ) % 37 } );\n    BOOST_CHECK_EQUAL( data_channel( 36 ), 0u );\n}\n\nusing all_but_one_channel_10 = all_but_one_channel< 10 >;\n\n/*\n * if the last channel (channel 36) is not within the map, it have to be remaped to 36 mod 36 == 0\n */\nBOOST_FIXTURE_TEST_CASE( all_but_one_channels_hop_10, all_but_one_channel_10 )\n{\n    BOOST_CHECK_EQUAL( data_channel( 0 ), 10u );\n    BOOST_CHECK_EQUAL( data_channel( 1 ), 20u );\n    // ...\n    BOOST_CHECK_EQUAL( data_channel( 10 ), 0u );\n    // ...\n    BOOST_CHECK_EQUAL( data_channel( 35 ), unsigned{ ( 36 * 10 ) % 37 } );\n    BOOST_CHECK_EQUAL( data_channel( 36 ), 0u );\n}\n\nstatic constexpr std::uint8_t a_few_channels_map[] = { 0x17, 0x44, 0x00, 0xff, 0x05 };\n\nusing only_a_few_channels_7 = fixture< 7, a_few_channels_map >;\n\n/* the list of channels in the map is:\n   0, 1, 2, 4, 10, 14, 24, 25, 26, 27, 28, 29, 30, 31, 32, 34\n   #Channels = 16\n */\nBOOST_FIXTURE_TEST_CASE( only_a_few_channels_hop_7, only_a_few_channels_7 )\n{\n    // we check the whole sequence\n    BOOST_CHECK_EQUAL( data_channel( 0  ), 25u ); // 7 % 16\n    BOOST_CHECK_EQUAL( data_channel( 1  ), 14u );\n    BOOST_CHECK_EQUAL( data_channel( 2  ), 14u ); // 21 % 16\n    BOOST_CHECK_EQUAL( data_channel( 3  ), 28u );\n    BOOST_CHECK_EQUAL( data_channel( 4  ), 4u  ); // 35 % 16\n    BOOST_CHECK_EQUAL( data_channel( 5  ), 14u ); // 5 % 16\n    BOOST_CHECK_EQUAL( data_channel( 6  ), 30u ); // 12 % 16\n    BOOST_CHECK_EQUAL( data_channel( 7  ), 4u  ); // 19 % 16\n    BOOST_CHECK_EQUAL( data_channel( 8  ), 26u );\n    BOOST_CHECK_EQUAL( data_channel( 9  ), 1u  ); // 33 % 16\n    BOOST_CHECK_EQUAL( data_channel( 10 ), 4u  ); // 3 % 16\n    BOOST_CHECK_EQUAL( data_channel( 11 ), 10u );\n    BOOST_CHECK_EQUAL( data_channel( 12 ), 1u  ); // 17 % 16\n    BOOST_CHECK_EQUAL( data_channel( 13 ), 24u );\n    BOOST_CHECK_EQUAL( data_channel( 14 ), 31u );\n    BOOST_CHECK_EQUAL( data_channel( 15 ), 1u  );\n    BOOST_CHECK_EQUAL( data_channel( 16 ), 26u ); // 8 % 16\n    BOOST_CHECK_EQUAL( data_channel( 17 ), 34u ); // 15 % 16\n    BOOST_CHECK_EQUAL( data_channel( 18 ), 24u ); // 22 % 16\n    BOOST_CHECK_EQUAL( data_channel( 19 ), 29u );\n    BOOST_CHECK_EQUAL( data_channel( 20 ), 10u ); // 36 % 16\n    BOOST_CHECK_EQUAL( data_channel( 21 ), 24u ); // 6 % 16\n    BOOST_CHECK_EQUAL( data_channel( 22 ), 31u ); // 13 % 16\n    BOOST_CHECK_EQUAL( data_channel( 23 ), 10u ); // 20 % 16\n    BOOST_CHECK_EQUAL( data_channel( 24 ), 27u );\n    BOOST_CHECK_EQUAL( data_channel( 25 ), 34u );\n    BOOST_CHECK_EQUAL( data_channel( 26 ), 4u  );\n    BOOST_CHECK_EQUAL( data_channel( 27 ), 29u ); // 11 % 16\n    BOOST_CHECK_EQUAL( data_channel( 28 ), 2u  ); // 18 % 16\n    BOOST_CHECK_EQUAL( data_channel( 29 ), 25u );\n    BOOST_CHECK_EQUAL( data_channel( 30 ), 32u );\n    BOOST_CHECK_EQUAL( data_channel( 31 ), 2u  );\n    BOOST_CHECK_EQUAL( data_channel( 32 ), 27u ); // 9 % 16\n    BOOST_CHECK_EQUAL( data_channel( 33 ), 0u  ); // 16 % 16\n    BOOST_CHECK_EQUAL( data_channel( 34 ), 25u ); // 23 % 16\n    BOOST_CHECK_EQUAL( data_channel( 35 ), 30u );\n    BOOST_CHECK_EQUAL( data_channel( 36 ), 0u  );\n}\n\n/*\n * A map just containing channel 0 and channel 36\n */\nstatic constexpr std::uint8_t only_two_channels_map[] = { 0x01, 0x00, 0x00, 0x00, 0x10 };\n\nusing only_two_channels_8 = fixture< 8, only_two_channels_map >;\n\nBOOST_FIXTURE_TEST_CASE( having_odd_hop_increment_with_two_channels_leeds_to_long_periods_on_the_same_channel, only_two_channels_8 )\n{\n    BOOST_CHECK_EQUAL( data_channel( 0  ), 0u );\n    BOOST_CHECK_EQUAL( data_channel( 1  ), 0u );\n    BOOST_CHECK_EQUAL( data_channel( 2  ), 0u );\n    // ...\n    BOOST_CHECK_EQUAL( data_channel( 34  ), 36u );\n    BOOST_CHECK_EQUAL( data_channel( 35  ), 36u );\n    BOOST_CHECK_EQUAL( data_channel( 36  ), 0u );\n}\n\n/*\n * A map just containing one channel\n */\nstatic const std::uint8_t only_one_channel_map[] = { 0x00, 0x04, 0x00, 0x00, 0x00 };\nstatic const std::uint8_t only_one_channel_and_some_rfu_bits_map[] = { 0x00, 0x04, 0x00, 0x00, 0x60 };\n\nusing only_two_channels_8 = fixture< 8, only_two_channels_map >;\n\n// 4.5.8.1 The minimum number of used channels shall be 2.\nBOOST_FIXTURE_TEST_CASE( channel_map_shall_contain_at_least_two_bits, bluetoe::link_layer::channel_map )\n{\n    BOOST_CHECK( !reset( only_one_channel_map, 5u ) );\n    BOOST_CHECK( !reset( only_one_channel_map, 11u ) );\n    BOOST_CHECK( !reset( only_one_channel_and_some_rfu_bits_map, 5u ) );\n    BOOST_CHECK( !reset( only_one_channel_and_some_rfu_bits_map, 11u ) );\n}\n\nBOOST_FIXTURE_TEST_CASE( invalid_hops_are_recognized, bluetoe::link_layer::channel_map )\n{\n    BOOST_CHECK( !reset( all_channel_map, 0 ) );\n    BOOST_CHECK( !reset( a_few_channels_map, 4 ) );\n    BOOST_CHECK( !reset( all_but_one_map, 17 ) );\n    BOOST_CHECK( !reset( all_channel_map, 99 ) );\n}\n\nBOOST_FIXTURE_TEST_CASE( valid_hops_are_recognized, bluetoe::link_layer::channel_map )\n{\n    BOOST_CHECK( reset( all_channel_map, 5 ) );\n    BOOST_CHECK( reset( a_few_channels_map, 7 ) );\n    BOOST_CHECK( reset( all_but_one_map, 10 ) );\n    BOOST_CHECK( reset( all_channel_map, 16 ) );\n}\n\nBOOST_FIXTURE_TEST_CASE( stores_the_right_hop, all_channel_5 )\n{\n    BOOST_CHECK( reset( only_two_channels_map ) );\n\n    BOOST_CHECK_EQUAL( data_channel( 0 ), 36u );\n    BOOST_CHECK_EQUAL( data_channel( 1 ), 0u );\n}\n\nstatic constexpr std::uint8_t all_but_25_map[] = { 0xff, 0xff, 0xff, 0xfd, 0x1f };\n\nusing all_channels_but_25 = all_channel< 6 >;\n\nBOOST_FIXTURE_TEST_CASE( real_life_example, all_channels_but_25 )\n{\n    BOOST_CHECK( reset( all_but_25_map ) );\n    BOOST_CHECK_EQUAL( data_channel( 28 ), 26u );\n    BOOST_CHECK_EQUAL( data_channel( 29 ), 32u );\n    BOOST_CHECK_EQUAL( data_channel( 30 ), 1u );\n    BOOST_CHECK_EQUAL( data_channel( 35 ), 31u );\n}\n"
  },
  {
    "path": "tests/link_layer/connected.hpp",
    "content": "#ifndef BLUETOE_TESTS_LINK_LAYER_CONNECTED_HPP\n#define BLUETOE_TESTS_LINK_LAYER_CONNECTED_HPP\n\n#include <boost/mpl/list.hpp>\n\n#include <initializer_list>\n#include <cstdint>\n#include <cassert>\n\n#include <bluetoe/link_layer.hpp>\n\n#include \"test_radio.hpp\"\n#include \"test_servers.hpp\"\n\n\nstatic const std::initializer_list< std::uint8_t > valid_connection_request_pdu =\n{\n    0xc5, 0x22,                         // header\n    0x3c, 0x1c, 0x62, 0x92, 0xf0, 0x48, // InitA: 48:f0:92:62:1c:3c (random)\n    0x47, 0x11, 0x08, 0x15, 0x0f, 0xc0, // AdvA:  c0:0f:15:08:11:47 (random)\n    0x5a, 0xb3, 0x9a, 0xaf,             // Access Address\n    0x08, 0x81, 0xf6,                   // CRC Init\n    0x03,                               // transmit window size\n    0x0b, 0x00,                         // window offset\n    0x18, 0x00,                         // interval (30ms)\n    0x00, 0x00,                         // peripheral latency\n    0x48, 0x00,                         // connection timeout (720ms)\n    0xff, 0xff, 0xff, 0xff, 0x1f,       // used channel map\n    0xaa                                // hop increment and sleep clock accuracy (10 and 50ppm)\n};\n\ntemplate < typename Server, template < std::size_t, std::size_t, typename > class Radio, typename ... Options >\nclass unconnected_base_t : public bluetoe::link_layer::link_layer< Server, Radio, Options... >\n{\npublic:\n    typedef bluetoe::link_layer::link_layer< Server, Radio, Options... > base;\n\n    unconnected_base_t()\n        : sequence_( 0 )\n        , next_expected_sequence_( 0 )\n    {\n    }\n\n    void run( unsigned times = 1 )\n    {\n        for ( ; times; --times )\n            base::run();\n    }\n\n    void check_not_connected( const char* test ) const\n    {\n        if ( !this->connection_events().empty() )\n        {\n            boost::test_tools::predicate_result result( false );\n            result.message() << \"in \" << test << \" check_not_connected failed.\";\n            BOOST_CHECK( result );\n        }\n    }\n\n    void add_connection_update_request(\n        std::uint8_t win_size, std::uint16_t win_offset, std::uint16_t interval,\n        std::uint16_t latency, std::uint16_t timeout, std::uint16_t instance )\n    {\n        ll_control_pdu( {\n            0x00,                                                   // opcode\n            win_size,\n            static_cast< std::uint8_t >( win_offset ),  static_cast< std::uint8_t >( win_offset >> 8 ),\n            static_cast< std::uint8_t >( interval ),    static_cast< std::uint8_t >( interval >> 8 ),\n            static_cast< std::uint8_t >( latency ),     static_cast< std::uint8_t >( latency >> 8 ),\n            static_cast< std::uint8_t >( timeout ),     static_cast< std::uint8_t >( timeout >> 8 ),\n            static_cast< std::uint8_t >( instance ),    static_cast< std::uint8_t >( instance >> 8 )\n        } );\n\n    }\n\n    void respond_with_connection_request( std::uint8_t window_size, std::uint16_t window_offset, std::uint16_t interval )\n    {\n        const std::vector< std::uint8_t > pdu =\n        {\n            0xc5, 0x22,                         // header\n            0x3c, 0x1c, 0x62, 0x92, 0xf0, 0x48, // InitA: 48:f0:92:62:1c:3c (random)\n            0x47, 0x11, 0x08, 0x15, 0x0f, 0xc0, // AdvA:  c0:0f:15:08:11:47 (random)\n            0x5a, 0xb3, 0x9a, 0xaf,             // Access Address\n            0x08, 0x81, 0xf6,                   // CRC Init\n            window_size,                        // transmit window size\n            static_cast< std::uint8_t >( window_offset & 0xff ),  // window offset\n            static_cast< std::uint8_t >( window_offset >> 8 ),\n            static_cast< std::uint8_t >( interval & 0xff ), // interval\n            static_cast< std::uint8_t >( interval >> 8 ),\n            0x00, 0x00,                         // peripheral latency\n            0x48, 0x00,                         // connection timeout\n            0xff, 0xff, 0xff, 0xff, 0x1f,       // used channel map\n            0xaa                                // hop increment and sleep clock accuracy\n        };\n\n        this->respond_to( 37, pdu );\n    }\n\n    void add_empty_pdus( unsigned count )\n    {\n        for ( ; count; --count )\n            ll_empty_pdu();\n    }\n\n    void add_ll_timeouts( unsigned count )\n    {\n        for ( ; count; --count )\n            this->add_connection_event_respond_timeout();\n    }\n\n    std::vector< std::uint8_t > run_single_ll_control_pdu( std::initializer_list< std::uint8_t > pdu )\n    {\n        this->respond_to( 37, valid_connection_request_pdu );\n        this->add_connection_event_respond( pdu );\n        this->add_connection_event_respond( { 0x01, 0x00 } );\n\n        this->run();\n\n        BOOST_REQUIRE_GE( this->connection_events().size(), 2u );\n        auto event = this->connection_events()[ 1 ];\n\n        BOOST_REQUIRE_EQUAL( event.transmitted_data.size(), 1u );\n\n        return event.transmitted_data[ 0 ].data;\n    }\n\n    void check_single_ll_control_pdu( std::initializer_list< std::uint8_t > pdu, std::initializer_list< std::uint8_t > expected_response, const char* label )\n    {\n        auto response = run_single_ll_control_pdu( pdu );\n        response[ 0 ] &= 0x03;\n\n        if ( response.size() != expected_response.size() || !std::equal( response.begin(), response.end(), expected_response.begin() ) )\n        {\n            boost::test_tools::predicate_result result( false );\n            result.message() << \"\\n\" << label << \": not expected response: \\n\";\n            result.message() << \"PDU:\\n\" << hex_dump( pdu.begin(), pdu.end() );\n            result.message() << \"expected:\\n\" << hex_dump( expected_response.begin(), expected_response.end() );\n            result.message() << \"found:\\n\" << hex_dump( response.begin(), response.end() );\n\n            BOOST_CHECK( result );\n\n        }\n    }\n\n    void ll_pdu( std::uint8_t llid, std::initializer_list< std::uint8_t > control )\n    {\n        std::vector< std::uint8_t > pdu = {\n            static_cast< std::uint8_t >( llid | sequence_ | next_expected_sequence_ ),\n            static_cast< std::uint8_t >( control.size() ) };\n        pdu.insert( pdu.end(), control.begin(), control.end() );\n\n        const test::connection_event_response response({ pdu });\n\n        this->add_connection_event_respond( response );\n        next_sequences();\n    }\n\n    void ll_control_pdu( std::initializer_list< std::uint8_t > control )\n    {\n        ll_pdu( 0x03, control );\n    }\n\n    void ll_function_call( std::function< void() > func )\n    {\n        std::function< test::pdu_list_t () > callback =\n            [=]() -> test::pdu_list_t\n            {\n                func();\n                const test::pdu_t empty{\n                    static_cast< std::uint8_t >( 0x01 | sequence_ | next_expected_sequence_ ), 0 };\n\n                return test::pdu_list_t( 1, empty );\n            };\n\n        this->add_connection_event_respond(\n            test::connection_event_response( callback ) );\n\n        next_sequences();\n    }\n\n    void ll_empty_pdu()\n    {\n        this->add_connection_event_respond( {\n            static_cast< std::uint8_t >( 0x01 | sequence_ | next_expected_sequence_ ), 0 } );\n        next_sequences();\n    }\n\n    void ll_empty_pdus( unsigned count )\n    {\n        for ( ; count; --count )\n            ll_empty_pdu();\n    }\n\n    void ll_data_pdu( std::initializer_list< std::uint8_t > control )\n    {\n        ll_pdu( 0x02, control );\n    }\nprivate:\n    void next_sequences()\n    {\n        sequence_ ^= 0x08;\n        next_expected_sequence_ ^= 0x04;\n    }\n\n    std::uint8_t sequence_;\n    std::uint8_t next_expected_sequence_;\n};\n\ntemplate < typename ... Options >\nusing unconnected_base = unconnected_base_t< test::small_temperature_service, test::radio, Options... >;\n\nstruct unconnected : unconnected_base< bluetoe::link_layer::buffer_sizes< 61u, 61u > > {};\n\ntemplate < typename ... Options >\nstruct connecting_base : unconnected_base< Options... >\n{\n    using base = unconnected_base< Options... >;\n\n    connecting_base()\n    {\n        this->respond_to( 37, valid_connection_request_pdu );\n\n        base::run();\n    }\n};\n\nusing connecting = connecting_base< bluetoe::link_layer::buffer_sizes< 61u, 61u > >;\n\n\nstruct connected_and_timeout : unconnected\n{\n    connected_and_timeout()\n    {\n        this->respond_to( 37, valid_connection_request_pdu );\n        this->add_connection_event_respond( { 1, 0 } );\n        this->add_connection_event_respond( { 1, 0 } );\n\n        base::run();\n    }\n};\n\ntypedef boost::mpl::list<\n    std::integral_constant< unsigned, 37u >,\n    std::integral_constant< unsigned, 38u >,\n    std::integral_constant< unsigned, 39u > > advertising_channels;\n\n#endif\n"
  },
  {
    "path": "tests/link_layer/connection_callbacks_tests.cpp",
    "content": "#define BOOST_TEST_MODULE\n#include <boost/test/included/unit_test.hpp>\n\n#include <bluetoe/link_layer.hpp>\n\n#include \"connected.hpp\"\n\nstruct only_requested_callback_t\n{\n    only_requested_callback_t()\n        : connection_requested_called( false )\n    {\n    }\n\n    template < typename ConnectionData >\n    void ll_connection_requested(\n        const bluetoe::link_layer::connection_details&      details,\n        const bluetoe::link_layer::connection_addresses&    addresses,\n        const ConnectionData& )\n    {\n        connection_requested_called = true;\n        reported_details            = details;\n        reported_addresses          = addresses;\n    }\n\n    bool                                        connection_requested_called;\n    bluetoe::link_layer::connection_details     reported_details;\n    bluetoe::link_layer::connection_addresses   reported_addresses;\n} only_requested_callback;\n\nstruct only_connect_attempt_timeout_callback_t\n{\n    only_connect_attempt_timeout_callback_t()\n        : connect_attempt_timeout_called( false )\n    {\n\n    }\n\n    template < typename ConnectionData >\n    void ll_connection_attempt_timeout( const ConnectionData& )\n    {\n        connect_attempt_timeout_called = true;\n    }\n\n    bool connect_attempt_timeout_called;\n\n} only_connect_attempt_timeout_callback;\n\nstruct only_connect_callback_t\n{\n    only_connect_callback_t()\n        : connection_established_called( false )\n    {\n    }\n\n    template < typename ConnectionData >\n    void ll_connection_established(\n        const bluetoe::link_layer::connection_details&      details,\n        const bluetoe::link_layer::connection_addresses&    addresses,\n        const ConnectionData& )\n    {\n        connection_established_called = true;\n        reported_details              = details;\n        reported_addresses            = addresses;\n    }\n\n    bool                                        connection_established_called;\n    bluetoe::link_layer::connection_details     reported_details;\n    bluetoe::link_layer::connection_addresses   reported_addresses;\n\n} only_connect_callback;\n\nstruct only_changed_callback_t\n{\n    only_changed_callback_t()\n        : only_changed_called( false )\n    {\n    }\n\n    template < typename ConnectionData >\n    void ll_connection_changed( const bluetoe::link_layer::connection_details& details, const ConnectionData& )\n    {\n        only_changed_called = true;\n        reported_details    = details;\n    }\n\n    bool                                    only_changed_called;\n    bluetoe::link_layer::connection_details reported_details;\n\n} only_changed_callback;\n\nstruct only_disconnect_callback_t\n{\n    only_disconnect_callback_t()\n        : only_disconnect_called( false )\n        , only_disconnect_reason( ~0 )\n    {\n    }\n\n    template < typename ConnectionData >\n    void ll_connection_closed( std::uint8_t reason, const ConnectionData& )\n    {\n        only_disconnect_reason = reason;\n        only_disconnect_called = true;\n    }\n\n    bool only_disconnect_called;\n    std::uint8_t only_disconnect_reason;\n\n} only_disconnect_callback;\n\nstruct only_version_callback_t\n{\n    only_version_callback_t()\n        : only_version_called( false )\n    {\n    }\n\n    template < typename ConnectionData >\n    void ll_version( std::uint8_t version, std::uint16_t company, std::uint16_t subversion, const ConnectionData& )\n    {\n        only_version_called = true;\n        version_version = version;\n        version_company = company;\n        version_subversion = subversion;\n    }\n\n    bool only_version_called;\n    std::uint8_t version_version;\n    std::uint16_t version_company;\n    std::uint16_t version_subversion;\n\n} only_version_callback;\n\nstruct only_rejected_callback_t\n{\n    only_rejected_callback_t()\n        : only_rejected_called( false )\n    {\n    }\n\n    template < typename ConnectionData >\n    void ll_rejected( std::uint8_t error_code, const ConnectionData&  )\n    {\n        only_rejected_called = true;\n        reject_error_code = error_code;\n    }\n\n    bool only_rejected_called;\n    std::uint8_t reject_error_code;\n\n} only_rejected_callback;\n\nstruct only_unknown_callback_t\n{\n    only_unknown_callback_t()\n        : only_unknown_called( false )\n    {\n    }\n\n    template < typename ConnectionData >\n    void ll_unknown( std::uint8_t unknown_type, const ConnectionData&  )\n    {\n        only_unknown_called = true;\n        unknown_unknown_type = unknown_type;\n    }\n\n    bool only_unknown_called;\n    std::uint8_t unknown_unknown_type;\n\n} only_unknown_callback;\n\nstruct only_remote_features_callback_t\n{\n    only_remote_features_callback_t()\n        : remote_features_called( false )\n    {\n        std::fill( remote_features, remote_features + 8, 0 );\n    }\n\n    template < typename ConnectionData >\n    void ll_remote_features( std::uint8_t rf[ 8 ], const ConnectionData& )\n    {\n        remote_features_called = true;\n        std::copy( rf, rf + 8, remote_features );\n    }\n\n    bool remote_features_called;\n    std::uint8_t remote_features[ 8 ];\n} only_remote_features_callback;\n\nstruct only_phy_updated_callback_t\n{\n    only_phy_updated_callback_t()\n        : phy_updated_called( false )\n    {\n    }\n\n    template < typename ConnectionData >\n    void ll_phy_updated(\n        bluetoe::link_layer::phy_ll_encoding::phy_ll_encoding_t te,\n        bluetoe::link_layer::phy_ll_encoding::phy_ll_encoding_t re,\n        const ConnectionData& )\n    {\n        phy_updated_called = true;\n        transmit_encoding = te;\n        receive_encoding  = re;\n    }\n\n    bool phy_updated_called;\n    bluetoe::link_layer::phy_ll_encoding::phy_ll_encoding_t transmit_encoding;\n    bluetoe::link_layer::phy_ll_encoding::phy_ll_encoding_t receive_encoding;\n} only_phy_updated_callback;\n\nstruct connect_and_disconnect_callback_t : only_connect_callback_t, only_disconnect_callback_t\n{\n\n} connect_and_disconnect_callback;\n\nstruct reset_callbacks\n{\n    reset_callbacks()\n    {\n        only_connect_callback = only_connect_callback_t();\n        only_changed_callback = only_changed_callback_t();\n        only_disconnect_callback = only_disconnect_callback_t();\n        connect_and_disconnect_callback = connect_and_disconnect_callback_t();\n        only_rejected_callback = only_rejected_callback_t();\n        only_remote_features_callback = only_remote_features_callback_t();\n        only_phy_updated_callback = only_phy_updated_callback_t();\n    }\n};\n\ntemplate < class LinkLayer >\nstruct mixin_reset_callbacks : private reset_callbacks, public LinkLayer {};\n\nusing link_layer_only_connect_callback = mixin_reset_callbacks<\n    unconnected_base<\n        bluetoe::link_layer::connection_callbacks< only_connect_callback_t, only_connect_callback >,\n        bluetoe::link_layer::sleep_clock_accuracy_ppm< 100u >,\n        bluetoe::link_layer::static_address< 0xc0, 0x0f, 0x15, 0x08, 0x11, 0x47 >,\n        test::buffer_sizes\n    >\n>;\n\nusing link_layer_only_changed_callback = mixin_reset_callbacks<\n    unconnected_base<\n        bluetoe::link_layer::connection_callbacks< only_changed_callback_t, only_changed_callback >,\n        bluetoe::link_layer::sleep_clock_accuracy_ppm< 100u >,\n        test::buffer_sizes\n    >\n>;\n\nusing link_layer_only_disconnect_callback = mixin_reset_callbacks<\n    unconnected_base<\n        bluetoe::link_layer::connection_callbacks< only_disconnect_callback_t, only_disconnect_callback >,\n        bluetoe::link_layer::sleep_clock_accuracy_ppm< 100u >,\n        test::buffer_sizes\n    >\n>;\n\nusing link_layer_connect_and_disconnect_callback = mixin_reset_callbacks<\n    unconnected_base<\n        bluetoe::link_layer::connection_callbacks< connect_and_disconnect_callback_t, connect_and_disconnect_callback >,\n        bluetoe::link_layer::sleep_clock_accuracy_ppm< 100u >,\n        bluetoe::link_layer::static_address< 0xc0, 0x0f, 0x15, 0x08, 0x11, 0x47 >,\n        test::buffer_sizes\n    >\n>;\n\nBOOST_FIXTURE_TEST_CASE( connection_is_not_established_before_the_first_connection_event, link_layer_only_connect_callback )\n{\n    BOOST_CHECK( !only_connect_callback.connection_established_called );\n\n    respond_to( 37, valid_connection_request_pdu );\n    run();\n\n    BOOST_CHECK( !only_connect_callback.connection_established_called );\n}\n\nBOOST_FIXTURE_TEST_CASE( timedout_connection_attempt_is_not_reported, link_layer_connect_and_disconnect_callback )\n{\n    respond_to( 37, valid_connection_request_pdu );\n    run();\n\n    BOOST_CHECK( !connect_and_disconnect_callback.connection_established_called );\n    BOOST_CHECK( !connect_and_disconnect_callback.only_disconnect_called );\n}\n\nBOOST_FIXTURE_TEST_CASE( connection_is_established_after_the_first_connection_event, link_layer_only_connect_callback )\n{\n    BOOST_CHECK( !only_connect_callback.connection_established_called );\n\n    respond_to( 37, valid_connection_request_pdu );\n    add_connection_event_respond( { 0, 1 } );\n    run( 5 );\n\n    BOOST_CHECK( only_connect_callback.connection_established_called );\n}\n\nBOOST_FIXTURE_TEST_CASE( connection_is_established_callback_called_only_once, link_layer_only_connect_callback )\n{\n    BOOST_CHECK( !only_connect_callback.connection_established_called );\n\n    respond_to( 37, valid_connection_request_pdu );\n    add_connection_event_respond( { 0, 1 } );\n    add_connection_event_respond( { 0, 1 } );\n    run( 5 );\n\n    BOOST_CHECK( only_connect_callback.connection_established_called );\n    only_connect_callback.connection_established_called = false;\n\n    run();\n    BOOST_CHECK( !only_connect_callback.connection_established_called );\n}\n\nnamespace {\n    bool equal( const bluetoe::link_layer::channel_map& lhs, const bluetoe::link_layer::channel_map& rhs )\n    {\n        for ( unsigned i = 0; i != bluetoe::link_layer::channel_map::max_number_of_data_channels; ++i )\n        {\n            if ( lhs.data_channel( i ) != rhs.data_channel( i ) )\n                return false;\n        }\n\n        return true;\n    }\n}\n\nBOOST_FIXTURE_TEST_CASE( connection_details_reported_when_connection_is_established, link_layer_only_connect_callback )\n{\n    respond_to( 37, {\n        0xc5, 0x22,                         // header\n        0x3c, 0x1c, 0x62, 0x92, 0xf0, 0x48, // InitA: 48:f0:92:62:1c:3c (random)\n        0x47, 0x11, 0x08, 0x15, 0x0f, 0xc0, // AdvA:  c0:0f:15:08:11:47 (random)\n        0x5a, 0xb3, 0x9a, 0xaf,             // Access Address\n        0x08, 0x81, 0xf6,                   // CRC Init\n        0x03,                               // transmit window size\n        0x0b, 0x00,                         // window offset\n        0x18, 0x00,                         // interval (30ms)\n        0x02, 0x00,                         // peripheral latency\n        0x48, 0x05,                         // connection timeout\n        0xf3, 0x5f, 0x1f, 0x7f, 0x1f,       // used channel map\n        0xaa                                // hop increment and sleep clock accuracy (10 and 50ppm)\n    } );\n    add_connection_event_respond( { 0, 1 } );\n    run( 2 );\n\n    const auto reported_details = only_connect_callback.reported_details;\n\n    static const std::uint8_t map_data[] = { 0xf3, 0x5f, 0x1f, 0x7f, 0x1f };\n    bluetoe::link_layer::channel_map channels;\n    channels.reset( &map_data[ 0 ], 10 );\n\n    BOOST_CHECK( equal( reported_details.channels(), channels ) );\n    BOOST_CHECK_EQUAL( reported_details.interval(), 0x18 );\n    BOOST_CHECK_EQUAL( reported_details.latency(), 2 );\n    BOOST_CHECK_EQUAL( reported_details.timeout(), 0x548 );\n    BOOST_CHECK_EQUAL( reported_details.cumulated_sleep_clock_accuracy_ppm(), unsigned{ 50 + 100 } );\n}\n\nBOOST_FIXTURE_TEST_CASE( addresses_reported_when_connection_established, link_layer_only_connect_callback )\n{\n    respond_to( 37, {\n        0x85, 0x22,                         // header\n        0x3c, 0x1c, 0x62, 0x92, 0xf0, 0x48, // InitA: 48:f0:92:62:1c:3c (public)\n        0x47, 0x11, 0x08, 0x15, 0x0f, 0xc0, // AdvA:  c0:0f:15:08:11:47 (random)\n        0x5a, 0xb3, 0x9a, 0xaf,             // Access Address\n        0x08, 0x81, 0xf6,                   // CRC Init\n        0x03,                               // transmit window size\n        0x0b, 0x00,                         // window offset\n        0x18, 0x00,                         // interval (30ms)\n        0x00, 0x00,                         // peripheral latency\n        0x48, 0x00,                         // connection timeout (720ms)\n        0xff, 0xff, 0xff, 0xff, 0x1f,       // used channel map\n        0xaa                                // hop increment and sleep clock accuracy (10 and 50ppm)\n    } );\n\n    add_connection_event_respond( { 0, 1 } );\n    run( 5 );\n\n    const auto reported_addresses = only_connect_callback.reported_addresses;\n    BOOST_CHECK_EQUAL( reported_addresses.remote_address(), bluetoe::link_layer::public_device_address( { 0x3c, 0x1c, 0x62, 0x92, 0xf0, 0x48 } ) );\n    BOOST_CHECK_EQUAL( reported_addresses.local_address(),  bluetoe::link_layer::random_device_address( { 0x47, 0x11, 0x08, 0x15, 0x0f, 0xc0 } ) );\n}\n\nBOOST_FIXTURE_TEST_CASE( connection_update_not_called_by_default, link_layer_only_changed_callback )\n{\n    BOOST_CHECK( !only_changed_callback.only_changed_called );\n\n    respond_to( 37, valid_connection_request_pdu );\n    add_connection_event_respond( { 0, 1 } );\n    run( 5 );\n\n    BOOST_CHECK( !only_changed_callback.only_changed_called );\n}\n\nBOOST_FIXTURE_TEST_CASE( connection_update, link_layer_only_changed_callback )\n{\n    BOOST_CHECK( !only_changed_callback.only_changed_called );\n\n    respond_to( 37, valid_connection_request_pdu );\n    add_connection_update_request( 5, 6, 40, 1, 25, 2 );\n    ll_empty_pdus( 120 );\n    run( 3u );\n\n    BOOST_CHECK( only_changed_callback.only_changed_called );\n}\n\nBOOST_FIXTURE_TEST_CASE( connection_details_reported_when_connection_is_updates, link_layer_only_changed_callback )\n{\n    respond_to( 37, valid_connection_request_pdu );\n    add_connection_update_request( 5, 6, 40, 1, 25, 2 );\n    ll_empty_pdus( 120 );\n    run( 3u );\n\n    static const std::uint8_t map_data[] = { 0xff, 0xff, 0xff, 0xff, 0x1f };\n    bluetoe::link_layer::channel_map channels;\n    channels.reset( &map_data[ 0 ], 10 );\n\n    const auto reported_details = only_changed_callback.reported_details;\n    BOOST_CHECK( equal( reported_details.channels(), channels ) );\n    BOOST_CHECK_EQUAL( reported_details.interval(), 40 );\n    BOOST_CHECK_EQUAL( reported_details.latency(), 1 );\n    BOOST_CHECK_EQUAL( reported_details.timeout(), 25 );\n    BOOST_CHECK_EQUAL( reported_details.cumulated_sleep_clock_accuracy_ppm(), unsigned{ 50 + 100 } );\n}\n\nBOOST_FIXTURE_TEST_CASE( never_connected, link_layer_only_disconnect_callback )\n{\n    run();\n\n    BOOST_CHECK( !only_disconnect_callback.only_disconnect_called );\n\n}\n\nBOOST_FIXTURE_TEST_CASE( connection_not_lost, link_layer_only_disconnect_callback )\n{\n    BOOST_CHECK( !only_disconnect_callback.only_disconnect_called );\n\n    respond_to( 37, valid_connection_request_pdu );\n    ll_empty_pdus( 120 );\n    run( 3 );\n\n    BOOST_CHECK( !only_disconnect_callback.only_disconnect_called );\n}\n\n/*\n * If the establishment of a new connection was never reported (because a connection event never happend)\n * the timeout of that connection attempt should not be reported\n */\nBOOST_FIXTURE_TEST_CASE( connection_lost_by_timeout_never_connected, link_layer_connect_and_disconnect_callback )\n{\n    BOOST_CHECK( !only_disconnect_callback.only_disconnect_called );\n\n    respond_to( 37, valid_connection_request_pdu );\n    run( 20 );\n\n    BOOST_CHECK( !only_connect_callback.connection_established_called );\n    BOOST_CHECK( !only_disconnect_callback.only_disconnect_called );\n}\n\nBOOST_FIXTURE_TEST_CASE( connection_lost_by_timeout, link_layer_only_disconnect_callback )\n{\n    BOOST_CHECK( !only_disconnect_callback.only_disconnect_called );\n\n    respond_to( 37, valid_connection_request_pdu );\n    ll_empty_pdus( 2 );\n    run( 20 );\n\n    BOOST_REQUIRE( only_disconnect_callback.only_disconnect_called );\n    BOOST_CHECK_EQUAL( only_disconnect_callback.only_disconnect_reason, 0x08 );\n}\n\nBOOST_FIXTURE_TEST_CASE( connection_lost_by_disconnect, link_layer_only_disconnect_callback )\n{\n    BOOST_CHECK( !only_disconnect_callback.only_disconnect_called );\n\n    respond_to( 37, valid_connection_request_pdu );\n    ll_empty_pdus( 3 );\n    add_connection_event_respond(\n        {\n            0x03, 0x02,\n            0x02, 0x12\n        } );\n\n    run( 4 );\n\n    BOOST_REQUIRE( only_disconnect_callback.only_disconnect_called );\n    BOOST_CHECK_EQUAL( only_disconnect_callback.only_disconnect_reason, 0x12 );\n}\n\nBOOST_FIXTURE_TEST_CASE( connection_closed, link_layer_only_disconnect_callback )\n{\n    BOOST_CHECK( !only_disconnect_callback.only_disconnect_called );\n\n    respond_to( 37, valid_connection_request_pdu );\n    ll_empty_pdus( 3 );\n    add_connection_event_respond([&](){\n        disconnect( 0x22 );\n    });\n\n    run( 4 );\n\n    BOOST_REQUIRE( only_disconnect_callback.only_disconnect_called );\n    BOOST_CHECK_EQUAL( only_disconnect_callback.only_disconnect_reason, 0x22 );\n}\n\nusing link_layer_only_version_callback = mixin_reset_callbacks<\n    unconnected_base<\n        bluetoe::link_layer::connection_callbacks< only_version_callback_t, only_version_callback >,\n        test::buffer_sizes\n    >\n>;\n\nBOOST_FIXTURE_TEST_CASE( version_indication, link_layer_only_version_callback )\n{\n    BOOST_CHECK( !only_disconnect_callback.only_disconnect_called );\n\n    respond_to( 37, valid_connection_request_pdu );\n    ll_empty_pdus( 3 );\n    add_connection_event_respond(\n        {\n            0x03, 0x06,\n            0x0c, 0x08, 0x22, 0x33, 0xbb, 0xaa\n        } );\n\n    run( 4 );\n\n    BOOST_REQUIRE( only_version_callback.only_version_called );\n    BOOST_CHECK_EQUAL( only_version_callback.version_version, 0x08 );\n    BOOST_CHECK_EQUAL( only_version_callback.version_company, 0x3322 );\n    BOOST_CHECK_EQUAL( only_version_callback.version_subversion, 0xaabb );\n}\n\nusing link_layer_only_requested_callback = mixin_reset_callbacks<\n    unconnected_base<\n        bluetoe::link_layer::connection_callbacks< only_requested_callback_t, only_requested_callback >,\n        test::buffer_sizes\n    >\n>;\n\nBOOST_FIXTURE_TEST_CASE( connection_request, link_layer_only_requested_callback )\n{\n    BOOST_CHECK( !only_requested_callback.connection_requested_called );\n\n    respond_to( 37, valid_connection_request_pdu );\n    run();\n\n    BOOST_CHECK( only_requested_callback.connection_requested_called );\n}\n\nusing link_layer_only_connect_attempt_timeout_callback = mixin_reset_callbacks<\n    unconnected_base<\n        bluetoe::link_layer::connection_callbacks< only_connect_attempt_timeout_callback_t, only_connect_attempt_timeout_callback >,\n        test::buffer_sizes\n    >\n>;\n\nBOOST_FIXTURE_TEST_CASE( connection_attempt_timeout, link_layer_only_connect_attempt_timeout_callback )\n{\n    BOOST_CHECK( !only_connect_attempt_timeout_callback.connect_attempt_timeout_called );\n\n    respond_to( 37, valid_connection_request_pdu );\n    run();\n\n    BOOST_CHECK( !only_connect_attempt_timeout_callback.connect_attempt_timeout_called );\n\n    run( 1000 );\n    BOOST_CHECK( only_connect_attempt_timeout_callback.connect_attempt_timeout_called );\n}\n\nusing link_layer_only_rejected_callback = mixin_reset_callbacks<\n    unconnected_base<\n        bluetoe::link_layer::connection_callbacks< only_rejected_callback_t, only_rejected_callback >,\n        test::buffer_sizes\n    >\n>;\n\nBOOST_FIXTURE_TEST_CASE( procedure_rejected, link_layer_only_rejected_callback )\n{\n    respond_to( 37, valid_connection_request_pdu );\n    ll_empty_pdus( 3 );\n    ll_control_pdu(\n        {\n            0x0D,                   // LL_REJECT_IND\n            0x42,                   // ErrorCode\n        }\n    );\n\n    run( 4 );\n\n    BOOST_REQUIRE( only_rejected_callback.only_rejected_called );\n    BOOST_CHECK_EQUAL( only_rejected_callback.reject_error_code, 0x42 );\n}\n\nBOOST_FIXTURE_TEST_CASE( procedure_ext_rejected, link_layer_only_rejected_callback )\n{\n    respond_to( 37, valid_connection_request_pdu );\n    ll_empty_pdus( 3 );\n    ll_control_pdu(\n        {\n            0x11,                   // LL_REJECT_EXT_IND\n            0xff,                   // opcode\n            0x42,                   // ErrorCode\n        }\n    );\n\n    run( 4 );\n\n    BOOST_REQUIRE( only_rejected_callback.only_rejected_called );\n    BOOST_CHECK_EQUAL( only_rejected_callback.reject_error_code, 0x42 );\n}\n\nusing link_layer_only_unknown_callback = mixin_reset_callbacks<\n    unconnected_base<\n        bluetoe::link_layer::connection_callbacks< only_unknown_callback_t, only_unknown_callback >,\n        test::buffer_sizes\n    >\n>;\n\n\nBOOST_FIXTURE_TEST_CASE( procedure_unknown, link_layer_only_unknown_callback )\n{\n    respond_to( 37, valid_connection_request_pdu );\n    ll_empty_pdus( 3 );\n    ll_control_pdu(\n        {\n            0x07,                   // LL_UNKNOWN_RSP\n            0x99,                   // UnknownType\n        }\n    );\n\n    run( 4 );\n\n    BOOST_REQUIRE( only_unknown_callback.only_unknown_called );\n    BOOST_CHECK_EQUAL( only_unknown_callback.unknown_unknown_type, 0x99 );\n}\n\nusing link_layer_only_remote_features_callback = mixin_reset_callbacks<\n    unconnected_base<\n        bluetoe::link_layer::connection_callbacks< only_remote_features_callback_t, only_remote_features_callback >,\n        test::buffer_sizes\n    >\n>;\n\nBOOST_FIXTURE_TEST_CASE( remote_features, link_layer_only_remote_features_callback )\n{\n    respond_to( 37, valid_connection_request_pdu );\n    ll_empty_pdus( 3 );\n    ll_control_pdu(\n        {\n            0x08,                   // LL_FEATURE_REQ\n            0x01, 0x02, 0x03, 0x04, // Feature set\n            0x05, 0x06, 0x07, 0x08\n        }\n    );\n\n    run( 4 );\n\n    static const std::uint8_t expected_features[] = {\n        0x01, 0x02, 0x03, 0x04,\n        0x05, 0x06, 0x07, 0x08\n    };\n\n    BOOST_REQUIRE( only_remote_features_callback.remote_features_called );\n    BOOST_CHECK_EQUAL_COLLECTIONS(\n        std::begin( only_remote_features_callback.remote_features ),\n        std::end( only_remote_features_callback.remote_features ),\n        std::begin( expected_features ),\n        std::end( expected_features ) );\n\n}\n\nusing link_layer_only_phy_updated_callback = mixin_reset_callbacks<\n    unconnected_base_t<\n        test::small_temperature_service,\n        test::radio_with_2mbit,\n        bluetoe::link_layer::connection_callbacks< only_phy_updated_callback_t, only_phy_updated_callback >,\n        test::buffer_sizes\n    >\n>;\n\nBOOST_FIXTURE_TEST_CASE( phy_update_test, link_layer_only_phy_updated_callback )\n{\n    respond_to( 37, valid_connection_request_pdu );\n    ll_empty_pdus( 3 );\n    ll_control_pdu(\n        {\n            0x18,                   // LL_PHY_UPDATE_IND\n            0x02,                   // PHY_C_TO_P\n            0x02,                   // PHY_P_TO_C\n            0x10, 0x00              // Instant\n        }\n    );\n\n    run( 40 );\n\n    BOOST_REQUIRE( only_phy_updated_callback.phy_updated_called );\n    BOOST_CHECK_EQUAL( only_phy_updated_callback.transmit_encoding, bluetoe::link_layer::phy_ll_encoding::le_2m_phy );\n    BOOST_CHECK_EQUAL( only_phy_updated_callback.receive_encoding, bluetoe::link_layer::phy_ll_encoding::le_2m_phy );\n}\n\nBOOST_FIXTURE_TEST_CASE( phy_update_test_II, link_layer_only_phy_updated_callback )\n{\n    respond_to( 37, valid_connection_request_pdu );\n    ll_empty_pdus( 3 );\n    ll_control_pdu(\n        {\n            0x18,                   // LL_PHY_UPDATE_IND\n            0x00,                   // PHY_C_TO_P unchanged\n            0x01,                   // PHY_P_TO_C 1MB\n            0x10, 0x00              // Instant\n        }\n    );\n\n    run( 40 );\n\n    BOOST_REQUIRE( only_phy_updated_callback.phy_updated_called );\n    BOOST_CHECK_EQUAL( only_phy_updated_callback.transmit_encoding, bluetoe::link_layer::phy_ll_encoding::le_unchanged_coding );\n    BOOST_CHECK_EQUAL( only_phy_updated_callback.receive_encoding, bluetoe::link_layer::phy_ll_encoding::le_1m_phy );\n}\n\nBOOST_FIXTURE_TEST_CASE( phy_update_test_III, link_layer_only_phy_updated_callback )\n{\n    respond_to( 37, valid_connection_request_pdu );\n    ll_empty_pdus( 3 );\n    ll_control_pdu(\n        {\n            0x18,                   // LL_PHY_UPDATE_IND\n            0x00,                   // PHY_C_TO_P unchanged\n            0x00,                   // PHY_P_TO_C unchanged\n            0x00, 0x00              // Instant\n        }\n    );\n\n    run( 40 );\n\n    BOOST_REQUIRE( only_phy_updated_callback.phy_updated_called );\n    BOOST_CHECK_EQUAL( only_phy_updated_callback.transmit_encoding, bluetoe::link_layer::phy_ll_encoding::le_unchanged_coding );\n    BOOST_CHECK_EQUAL( only_phy_updated_callback.receive_encoding, bluetoe::link_layer::phy_ll_encoding::le_unchanged_coding );\n}\n\nBOOST_FIXTURE_TEST_CASE( multiple_events, link_layer_only_connect_callback )\n{\n    respond_to( 37, valid_connection_request_pdu );\n    ll_control_pdu(\n        {\n            0x0c, 0x08, 0x22, 0x33, 0xbb, 0xaa\n        }\n    );\n    ll_empty_pdus( 1 );\n\n    run( 4 );\n\n    const auto reported_details = only_connect_callback.reported_details;\n\n    static const std::uint8_t map_data[] = { 0xff, 0xff, 0xff, 0xff, 0xff };\n    bluetoe::link_layer::channel_map channels;\n    channels.reset( &map_data[ 0 ], 10 );\n\n    BOOST_CHECK( equal( reported_details.channels(), channels ) );\n    BOOST_CHECK_EQUAL( reported_details.interval(), 0x18 );\n    BOOST_CHECK_EQUAL( reported_details.latency(), 0 );\n    BOOST_CHECK_EQUAL( reported_details.timeout(), 72 );\n    BOOST_CHECK_EQUAL( reported_details.cumulated_sleep_clock_accuracy_ppm(), unsigned{ 50 + 100 } );\n}\n"
  },
  {
    "path": "tests/link_layer/connection_event_callback_tests.cpp",
    "content": "#define BOOST_TEST_MODULE\n#include <boost/test/included/unit_test.hpp>\n\n#include <bluetoe/connection_event_callback.hpp>\n\n#include \"connected.hpp\"\n\n#include <sstream>\n\nstruct callbacks_t {\n\n    struct connection {\n        connection() : value( 0 ) {}\n\n        int value;\n    };\n\n    unsigned ll_synchronized_callback( unsigned instant, connection& con )\n    {\n        connection_values.push_back( con.value );\n        ++con.value;\n        instants.push_back( instant );\n\n        if ( !planned_latency.empty() )\n        {\n            const auto result = planned_latency.front();\n            planned_latency.erase( planned_latency.begin() );\n\n            return result;\n        }\n\n        return 0;\n    }\n\n    std::vector< unsigned > planned_latency;\n    std::vector< int >      connection_values;\n    std::vector< unsigned > instants;\n\n} callbacks;\n\nusing bluetoe::link_layer::delta_time;\n\nnamespace {\n    template < class T >\n    T take( const T& c, std::size_t n )\n    {\n        return T{ c.begin(), std::next(c.begin(), std::min( n, c.size() ) ) };\n    }\n}\n\n/*\n * Set of test that should not compile.\n */\nBOOST_AUTO_TEST_SUITE( tests_that_should_not_compile )\n\n#if 0\nBOOST_AUTO_TEST_CASE( no_support_by_hardware )\n{\n    using gatt = unconnected_base_t<\n        test::small_temperature_service,\n        test::radio_without_user_timer,\n        bluetoe::link_layer::synchronized_connection_event_callback< callbacks_t, callbacks, 1000, -100, 100 >\n     >;\n\n     gatt g;\n}\n#endif\n\n#if 0\nBOOST_AUTO_TEST_CASE( MaximumPeriodUS_less_or_equal_minimum_interval )\n{\n    using gatt = unconnected_base_t<\n        test::small_temperature_service,\n        test::radio_with_user_timer,\n        bluetoe::link_layer::synchronized_connection_event_callback< callbacks_t, callbacks, 8000, -100, 100 >,\n        bluetoe::link_layer::check_synchronized_connection_event_callback\n     >;\n\n     gatt g;\n}\n#endif\n\n#if 0\nBOOST_AUTO_TEST_CASE( PhaseShiftUS_is_negative )\n{\n    using gatt = unconnected_base_t<\n        test::small_temperature_service,\n        test::radio_with_user_timer,\n        bluetoe::link_layer::synchronized_connection_event_callback< callbacks_t, callbacks, 2500, 100, 100 >,\n        bluetoe::link_layer::check_synchronized_connection_event_callback\n     >;\n\n     gatt g;\n}\n#endif\n\n#if 0\nBOOST_AUTO_TEST_CASE( PhaseShiftGreaterThan_SetupTime )\n{\n    using gatt = unconnected_base_t<\n        test::small_temperature_service,\n        test::radio_with_user_timer,\n        bluetoe::link_layer::synchronized_connection_event_callback< callbacks_t, callbacks, 2500, -50, 100 >,\n        bluetoe::link_layer::check_synchronized_connection_event_callback\n     >;\n\n     gatt g;\n}\n#endif\n\n#if 0\nBOOST_AUTO_TEST_CASE( PhaseShiftGreaterThanRuntimerAndSetuptime)\n{\n    using gatt = unconnected_base_t<\n        test::small_temperature_service,\n        test::radio_with_user_timer,\n        bluetoe::link_layer::synchronized_connection_event_callback< callbacks_t, callbacks, 2500, -300, 350 >,\n        bluetoe::link_layer::check_synchronized_connection_event_callback\n     >;\n\n     gatt g;\n}\n#endif\n\n#if 0\nBOOST_AUTO_TEST_CASE( ShiftExceedsPeriod )\n{\n    using gatt = unconnected_base_t<\n        test::small_temperature_service,\n        test::radio_with_user_timer,\n        bluetoe::link_layer::synchronized_connection_event_callback< callbacks_t, callbacks, 200, -300, 100 >,\n        bluetoe::link_layer::check_synchronized_connection_event_callback\n     >;\n\n     gatt g;\n}\n#endif\n\n#if 0\nBOOST_AUTO_TEST_CASE( MaximumExecutionTimeLessThanHalfOfPeriod )\n{\n    using gatt = unconnected_base_t<\n        test::small_temperature_service,\n        test::radio_with_user_timer,\n        bluetoe::link_layer::synchronized_connection_event_callback< callbacks_t, callbacks, 1000, -700, 600 >,\n        bluetoe::link_layer::check_synchronized_connection_event_callback\n     >;\n\n     gatt g;\n}\n#endif\n\nBOOST_AUTO_TEST_SUITE_END()\n\ntemplate < unsigned MinimumPeriodUS, int PhaseShiftUS, unsigned MaximumExecutionTimeUS = 0 >\nstruct unconnected_server : unconnected_base_t<\n    test::small_temperature_service,\n    test::radio_with_user_timer,\n    bluetoe::link_layer::synchronized_connection_event_callback< callbacks_t, callbacks, MinimumPeriodUS, PhaseShiftUS, MaximumExecutionTimeUS >\n >\n {\n    unconnected_server()\n    {\n        callbacks = callbacks_t();\n    }\n };\n\nusing server_7ms_minus_100us  = unconnected_server< 7000, -100 >;\nusing server_7ms_plus_100us   = unconnected_server< 7000, 100 >;\nusing server_15ms_minus_100us = unconnected_server< 15000, -100 >;\n\nBOOST_FIXTURE_TEST_CASE( callback_not_called_if_unconnected, server_7ms_minus_100us )\n{\n    run();\n\n    BOOST_CHECK( callbacks.connection_values.empty() );\n    BOOST_CHECK_EQUAL( scheduled_user_timers().size(), 0u );\n}\n\nBOOST_FIXTURE_TEST_CASE( callback_called_with_correct_period_and_phase, server_7ms_minus_100us )\n{\n    // 30ms interval -> effective period: 6ms\n    this->respond_to( 37, valid_connection_request_pdu );\n    ll_empty_pdu();\n    ll_empty_pdu();\n    ll_empty_pdu();\n\n    run();\n\n    const auto timers = scheduled_user_timers();\n\n    BOOST_REQUIRE_GT( timers.size(), 7u );\n\n    BOOST_CHECK_EQUAL( timers[ 0 ].delay, bluetoe::link_layer::delta_time::msec( 6 ) - bluetoe::link_layer::delta_time::usec( 100 ) );\n    BOOST_CHECK_EQUAL( timers[ 1 ].delay, bluetoe::link_layer::delta_time::msec( 12 ) - bluetoe::link_layer::delta_time::usec( 100 ) );\n    BOOST_CHECK_EQUAL( timers[ 2 ].delay, bluetoe::link_layer::delta_time::msec( 18 ) - bluetoe::link_layer::delta_time::usec( 100 ) );\n    BOOST_CHECK_EQUAL( timers[ 3 ].delay, bluetoe::link_layer::delta_time::msec( 24 ) - bluetoe::link_layer::delta_time::usec( 100 ) );\n    BOOST_CHECK_EQUAL( timers[ 4 ].delay, bluetoe::link_layer::delta_time::msec( 30 ) - bluetoe::link_layer::delta_time::usec( 100 ) );\n    BOOST_CHECK_EQUAL( timers[ 5 ].delay, bluetoe::link_layer::delta_time::msec( 36 ) - bluetoe::link_layer::delta_time::usec( 100 ) );\n    BOOST_CHECK_EQUAL( timers[ 6 ].delay, bluetoe::link_layer::delta_time::msec( 12 ) - bluetoe::link_layer::delta_time::usec( 100 ) );\n}\n\nBOOST_FIXTURE_TEST_CASE( callback_called_with_correct_period_and_positive_phase, server_7ms_plus_100us )\n{\n    // 30ms interval -> effective period: 6ms\n    this->respond_to( 37, valid_connection_request_pdu );\n    ll_empty_pdu();\n    ll_empty_pdu();\n    ll_empty_pdu();\n\n    run();\n\n    const auto timers = scheduled_user_timers();\n\n    BOOST_REQUIRE_GT( timers.size(), 7u );\n\n    BOOST_CHECK_EQUAL( timers[ 0 ].delay, bluetoe::link_layer::delta_time::msec( 6 ) + bluetoe::link_layer::delta_time::usec( 100 ) );\n    BOOST_CHECK_EQUAL( timers[ 1 ].delay, bluetoe::link_layer::delta_time::msec( 12 ) + bluetoe::link_layer::delta_time::usec( 100 ) );\n    BOOST_CHECK_EQUAL( timers[ 2 ].delay, bluetoe::link_layer::delta_time::msec( 18 ) + bluetoe::link_layer::delta_time::usec( 100 ) );\n    BOOST_CHECK_EQUAL( timers[ 3 ].delay, bluetoe::link_layer::delta_time::msec( 24 ) + bluetoe::link_layer::delta_time::usec( 100 ) );\n    BOOST_CHECK_EQUAL( timers[ 4 ].delay, bluetoe::link_layer::delta_time::msec( 30 ) + bluetoe::link_layer::delta_time::usec( 100 ) );\n    BOOST_CHECK_EQUAL( timers[ 5 ].delay, bluetoe::link_layer::delta_time::msec( 6 ) + bluetoe::link_layer::delta_time::usec( 100 ) );\n    BOOST_CHECK_EQUAL( timers[ 6 ].delay, bluetoe::link_layer::delta_time::msec( 12 ) + bluetoe::link_layer::delta_time::usec( 100 ) );\n}\n\nBOOST_FIXTURE_TEST_CASE( using_latency, server_7ms_minus_100us )\n{\n    callbacks.planned_latency = { 0, 4u, 1u, 0, 17u };\n    this->respond_to( 37, valid_connection_request_pdu );\n    ll_empty_pdu();\n    ll_empty_pdu();\n    ll_empty_pdu();\n\n    run();\n\n    const auto timers = scheduled_user_timers();\n\n    BOOST_REQUIRE_GT( timers.size(), 7u );\n\n    BOOST_CHECK_EQUAL( timers[ 0 ].delay, bluetoe::link_layer::delta_time::msec( 6 ) - bluetoe::link_layer::delta_time::usec( 100 ) );\n    BOOST_CHECK_EQUAL( timers[ 1 ].delay, bluetoe::link_layer::delta_time::msec( 12 ) - bluetoe::link_layer::delta_time::usec( 100 ) );\n    BOOST_CHECK_EQUAL( timers[ 2 ].delay, bluetoe::link_layer::delta_time::msec( 18 ) - bluetoe::link_layer::delta_time::usec( 100 ) );\n    BOOST_CHECK_EQUAL( timers[ 3 ].delay, bluetoe::link_layer::delta_time::msec( 24 ) - bluetoe::link_layer::delta_time::usec( 100 ) );\n    BOOST_CHECK_EQUAL( timers[ 4 ].delay, bluetoe::link_layer::delta_time::msec( 30 ) - bluetoe::link_layer::delta_time::usec( 100 ) );\n    BOOST_CHECK_EQUAL( timers[ 5 ].delay, bluetoe::link_layer::delta_time::msec( 36 ) - bluetoe::link_layer::delta_time::usec( 100 ) );\n    BOOST_CHECK_EQUAL( timers[ 6 ].delay, bluetoe::link_layer::delta_time::msec( 12 ) - bluetoe::link_layer::delta_time::usec( 100 ) );\n}\n\nBOOST_FIXTURE_TEST_CASE( force_callback_call_while_using_latency, server_7ms_minus_100us )\n{\n    callbacks.planned_latency = { 2u, 2u, 2u, 2u, 2u, 2u };\n    this->respond_to( 37, valid_connection_request_pdu );\n    ll_empty_pdu();\n    ll_function_call([this](){\n        force_synchronized_connection_event_callback();\n    });\n    ll_empty_pdu();\n\n    run();\n\n    static const auto expected = {\n        0u,        3u,\n        0u,        3u,    // at the second connection event, the\n                          // callback is forces\n            1u,        4u\n    };\n\n    BOOST_TEST(\n        take( callbacks.instants, expected.size() ) == expected,\n        boost::test_tools::per_element() );\n}\n\nBOOST_FIXTURE_TEST_CASE( correct_instance, server_7ms_minus_100us )\n{\n    this->respond_to( 37, valid_connection_request_pdu );\n    ll_empty_pdu();\n    ll_empty_pdu();\n    ll_empty_pdu();\n\n    run();\n\n    static const auto expected = {\n        0u, 1u, 2u, 3u, 4u,\n        0u, 1u, 2u, 3u, 4u,\n        0u };\n\n    BOOST_TEST(\n        take( callbacks.instants, expected.size() ) == expected,\n        boost::test_tools::per_element() );\n}\n\nBOOST_FIXTURE_TEST_CASE( correct_instance_with_instance, server_7ms_minus_100us )\n{\n    callbacks.planned_latency = { 0, 4u, 1u, 0, 2u };\n    this->respond_to( 37, valid_connection_request_pdu );\n    ll_empty_pdu();\n    ll_empty_pdu();\n    ll_empty_pdu();\n\n    run();\n\n    static const auto expected = {\n        0u, 1u,\n            1u,    3u, 4u,\n                2u };\n\n    BOOST_TEST(\n        take( callbacks.instants, expected.size() ) == expected,\n        boost::test_tools::per_element() );\n}\n\nBOOST_FIXTURE_TEST_CASE( use_default_constructed_connection_and_persist_connection, server_7ms_minus_100us )\n{\n    this->respond_to( 37, valid_connection_request_pdu );\n    ll_empty_pdu();\n    ll_empty_pdu();\n    ll_empty_pdu();\n\n    run();\n\n    const auto connection_values = callbacks.connection_values;\n\n    BOOST_REQUIRE_GT( connection_values.size(), 5u );\n\n    BOOST_CHECK_EQUAL( connection_values[ 0 ], 0 );\n    BOOST_CHECK_EQUAL( connection_values[ 1 ], 1 );\n    BOOST_CHECK_EQUAL( connection_values[ 2 ], 2 );\n}\n\nBOOST_FIXTURE_TEST_CASE( reset_connection_after_reconnect, server_15ms_minus_100us )\n{\n    this->respond_to( 37, valid_connection_request_pdu );\n    ll_empty_pdu();\n    ll_control_pdu( {\n        0x02,           // LL_TERMINATE_IND\n        0x13            // REMOTE USER TERMINATED CONNECTION\n    } );\n\n    this->respond_to( 37, valid_connection_request_pdu );\n    ll_empty_pdu();\n    run();\n\n    static const auto expected = { 0, 1, 0, 1, 2 };\n\n    BOOST_TEST(\n        take( callbacks.connection_values, expected.size() ) == expected,\n        boost::test_tools::per_element() );\n}\n\n/*\n * Test with MinimumPeriodUS equal a multiple of the interval\n */\nusing server_60ms_minus_100us  = unconnected_server< 60000, -100 >;\n\nBOOST_FIXTURE_TEST_CASE( larger_min_period, server_60ms_minus_100us )\n{\n    this->respond_to( 37, valid_connection_request_pdu );\n    ll_empty_pdus( 30 );\n\n    run();\n\n    const auto timers = scheduled_user_timers();\n\n    BOOST_REQUIRE_GT( timers.size(), 7u );\n\n    BOOST_CHECK_EQUAL( timers[ 0 ].delay, delta_time::msec( 60 ) - bluetoe::link_layer::delta_time::usec( 100 ) );\n    BOOST_CHECK_EQUAL( timers[ 1 ].delay, delta_time::msec( 120 ) - bluetoe::link_layer::delta_time::usec( 100 ) );\n    BOOST_CHECK_EQUAL( timers[ 2 ].delay, delta_time::msec( 120 ) - bluetoe::link_layer::delta_time::usec( 100 ) );\n    BOOST_CHECK_EQUAL( timers[ 3 ].delay, delta_time::msec( 120 ) - bluetoe::link_layer::delta_time::usec( 100 ) );\n    BOOST_CHECK_EQUAL( timers[ 4 ].delay, delta_time::msec( 120 ) - bluetoe::link_layer::delta_time::usec( 100 ) );\n    BOOST_CHECK_EQUAL( timers[ 5 ].delay, delta_time::msec( 120 ) - bluetoe::link_layer::delta_time::usec( 100 ) );\n    BOOST_CHECK_EQUAL( timers[ 6 ].delay, delta_time::msec( 120 ) - bluetoe::link_layer::delta_time::usec( 100 ) );\n    BOOST_CHECK_EQUAL( timers[ 7 ].delay, delta_time::msec( 120 ) - bluetoe::link_layer::delta_time::usec( 100 ) );\n}\n\nBOOST_FIXTURE_TEST_CASE( larger_min_period_instance, server_60ms_minus_100us )\n{\n    this->respond_to( 37, valid_connection_request_pdu );\n    ll_empty_pdu();\n    ll_empty_pdu();\n\n    run();\n\n    static const auto expected = { 0u, 0u, 0u, 0u };\n\n    BOOST_TEST(\n        take( callbacks.instants, expected.size() ) == expected,\n        boost::test_tools::per_element() );\n}\n\nusing server_20ms_minus_100us  = unconnected_server< 20000, -100 >;\n\nBOOST_FIXTURE_TEST_CASE( reconnect_with_different_interval, server_20ms_minus_100us )\n{\n    this->respond_to( 37, valid_connection_request_pdu );\n    ll_empty_pdu();\n    ll_control_pdu( {\n        0x02,           // LL_TERMINATE_IND\n        0x13            // REMOTE USER TERMINATED CONNECTION\n    } );\n\n    this->respond_to( 37, {\n        0xc5, 0x22,                         // header\n        0x3c, 0x1c, 0x62, 0x92, 0xf0, 0x48, // InitA: 48:f0:92:62:1c:3c (random)\n        0x47, 0x11, 0x08, 0x15, 0x0f, 0xc0, // AdvA:  c0:0f:15:08:11:47 (random)\n        0x5a, 0xb3, 0x9a, 0xaf,             // Access Address\n        0x08, 0x81, 0xf6,                   // CRC Init\n        0x03,                               // transmit window size\n        0x08, 0x00,                         // window offset\n        0x08, 0x00,                         // interval (10ms)\n        0x00, 0x00,                         // peripheral latency\n        0x48, 0x00,                         // connection timeout (720ms)\n        0xff, 0xff, 0xff, 0xff, 0x1f,       // used channel map\n        0xaa                                // hop increment and sleep clock accuracy (10 and 50ppm)\n    } );\n    ll_empty_pdu();\n    run();\n\n    const auto timers = scheduled_user_timers();\n    BOOST_REQUIRE_GT( timers.size(), 3u );\n\n    BOOST_CHECK_EQUAL( timers[ 0 ].delay, delta_time::msec( 15 ) - bluetoe::link_layer::delta_time::usec( 100 ) );\n    BOOST_CHECK_EQUAL( timers[ 1 ].delay, delta_time::msec( 30 ) - bluetoe::link_layer::delta_time::usec( 100 ) );\n\n    BOOST_CHECK_EQUAL( timers[ 2 ].delay, delta_time::msec( 20 ) - bluetoe::link_layer::delta_time::usec( 100 ) );\n    BOOST_CHECK_EQUAL( timers[ 3 ].delay, delta_time::msec( 40 ) - bluetoe::link_layer::delta_time::usec( 100 ) );\n}\n\nBOOST_FIXTURE_TEST_CASE( changed_interval_on_connection_update, server_20ms_minus_100us )\n{\n    this->respond_to( 37, valid_connection_request_pdu );\n    ll_empty_pdu();\n    add_connection_update_request(\n        0x08, 0x08, 0x08, 0, 100, 8 );\n    ll_empty_pdus( 30 );\n    run();\n\n    const auto timers = scheduled_user_timers();\n    BOOST_REQUIRE_GT( timers.size(), 16u );\n\n    // instance 0\n    BOOST_CHECK_EQUAL( timers[ 0 ].delay, delta_time::msec( 15 ) - bluetoe::link_layer::delta_time::usec( 100 ) );\n    BOOST_CHECK_EQUAL( timers[ 1 ].delay, delta_time::msec( 30 ) - bluetoe::link_layer::delta_time::usec( 100 ) );\n\n    // ...\n    BOOST_CHECK_EQUAL( timers[ 13 ].delay, delta_time::msec( 30 ) - bluetoe::link_layer::delta_time::usec( 100 ) );\n    BOOST_CHECK_EQUAL( timers[ 14 ].delay, delta_time::msec( 20 ) - bluetoe::link_layer::delta_time::usec( 100 ) );\n    BOOST_CHECK_EQUAL( timers[ 15 ].delay, delta_time::msec( 40 ) - bluetoe::link_layer::delta_time::usec( 100 ) );\n    BOOST_CHECK_EQUAL( timers[ 16 ].delay, delta_time::msec( 40 ) - bluetoe::link_layer::delta_time::usec( 100 ) );\n}\n\nstruct callbacks_with_optional_callbacks_t\n{\n    struct connection {\n        connection() : value( 0 ) {}\n\n        int value;\n    };\n\n    unsigned ll_synchronized_callback( unsigned, connection& )\n    {\n        return 0;\n    }\n\n    connection ll_synchronized_callback_connect(\n        bluetoe::link_layer::delta_time connection_interval,\n        unsigned                        calls_per_interval )\n    {\n        out << \"connect: \" << connection_interval << \", \" << calls_per_interval << \"\\n\";\n\n        return connection();\n    }\n\n    void ll_synchronized_callback_period_update(\n        bluetoe::link_layer::delta_time connection_interval,\n        unsigned                        calls_per_interval,\n        connection&                     con )\n    {\n        ++con.value;\n        out << \"update: \" << connection_interval << \", \" << calls_per_interval << \", \" << con.value << \"\\n\";\n    }\n\n    void ll_synchronized_callback_disconnect( connection& con )\n    {\n        ++con.value;\n        out << \"disconnect: \" << con.value << \"\\n\";\n    }\n\n    std::ostringstream out;\n} callbacks_with_optional_callbacks;\n\ntemplate < unsigned MinimumPeriodUS, int PhaseShiftUS, unsigned MaximumExecutionTimeUS = 0 >\nstruct unconnected_server_with_cbs : unconnected_base_t<\n    test::small_temperature_service,\n    test::radio_with_user_timer,\n    bluetoe::link_layer::synchronized_connection_event_callback< callbacks_with_optional_callbacks_t, callbacks_with_optional_callbacks, MinimumPeriodUS, PhaseShiftUS, MaximumExecutionTimeUS >\n >\n {\n    unconnected_server_with_cbs()\n    {\n        callbacks_with_optional_callbacks = callbacks_with_optional_callbacks_t();\n    }\n\n    std::vector< std::string > history() const\n    {\n        std::vector<std::string> result;\n\n        std::stringstream input( callbacks_with_optional_callbacks.out.str() );\n        std::string item;\n\n        while ( std::getline( input, item, '\\n' ) )\n            result.push_back( item );\n\n        return result;\n    }\n };\n\nusing server_20ms_minus_100us_cbs  = unconnected_server_with_cbs< 20000, -100 >;\n\nBOOST_FIXTURE_TEST_CASE( no_callbacks, server_20ms_minus_100us_cbs )\n{\n    BOOST_TEST( callbacks_with_optional_callbacks.out.str() == \"\" );\n}\n\nBOOST_FIXTURE_TEST_CASE( connect_disconnect_callbacks, server_20ms_minus_100us_cbs )\n{\n    this->respond_to( 37, valid_connection_request_pdu );\n    ll_empty_pdu();\n    ll_control_pdu( {\n        0x02,           // LL_TERMINATE_IND\n        0x13            // REMOTE USER TERMINATED CONNECTION\n    } );\n    ll_empty_pdu();\n    run();\n\n    const auto hist = history();\n    BOOST_REQUIRE_GT( hist.size(), 1u );\n\n    BOOST_TEST( hist[ 0 ] == \"connect: 30ms, 2\" );\n    BOOST_TEST( hist[ 1 ] == \"disconnect: 1\" );\n}\n\nBOOST_FIXTURE_TEST_CASE( update_callback, server_20ms_minus_100us_cbs )\n{\n    this->respond_to( 37, valid_connection_request_pdu );\n    ll_empty_pdu();\n    add_connection_update_request(\n        0x08, 0x08, 0x08, 0, 100, 8 );\n    ll_empty_pdus( 10 );\n    run();\n\n    const auto hist = history();\n    BOOST_REQUIRE_GT( hist.size(), 1u );\n\n    BOOST_TEST( hist[ 0 ] == \"connect: 30ms, 2\" );\n    BOOST_TEST( hist[ 1 ] == \"update: 10ms, 0, 1\" );\n}\n"
  },
  {
    "path": "tests/link_layer/connection_parameter_update_procedure_tests.cpp",
    "content": "#define BOOST_TEST_MODULE\n#include <boost/test/included/unit_test.hpp>\n\n#include \"buffer_io.hpp\"\n#include \"connected.hpp\"\n\n#include <bluetoe/link_layer.hpp>\n#include <bluetoe/l2cap_signaling_channel.hpp>\n\n\nusing namespace test;\n\n/*\n * To request the update of the connection parameters, a peripheral / link layer peripheral\n * has two options:\n * - LL Connection Parameters Request Procedure (ll)\n * - L2CAP Connection Parameter Update Request (l2cap)\n *\n * Where the standard prefers the the former, if both, peripheral and central supports\n * that procedure.\n *\n * So, to pick one of them, its crucial to know whether the central supports the\n * LL Connection Parameters Request Procedure.\n *\n * Lets start by assuming, that the central implements the LL Connection Parameters Request Procedure.\n * If a LL_VERSION_IND is received from the central indicating, that the centrals link layer version\n * is 4.0 (or less), then the central does not implement LL Connection Parameters Request Procedure.\n * If a LL_FEATURE_REQ PDU is received, it's clear whether the central implements the\n * LL Connection Parameters Request Procedure or not.\n *\n * LL Connection Parameters Request Procedure should be optional, so if the peripheral votes to not implement\n * LL Connection Parameters Request Procedure, than we should default to l2cap.\n */\n\nstruct link_layer_with_signaling_channel : unconnected_base< bluetoe::l2cap::signaling_channel<>, test::buffer_sizes >\n{\n    link_layer_with_signaling_channel()\n    {\n        respond_to( 37, valid_connection_request_pdu );\n    }\n};\n\nBOOST_FIXTURE_TEST_CASE( if_central_protocol_version_is_unknown_try_ll, link_layer_with_signaling_channel )\n{\n    add_connection_event_respond(\n        [&](){\n            BOOST_REQUIRE( connection_parameter_update_request( 10, 20, 3, 2 * 20 * 4 ) );\n        });\n\n    ll_empty_pdus(3);\n\n    run( 5 );\n\n    check_outgoing_ll_control_pdu( {\n        0x0F,                       // opcode\n        10, 0x00,                   // min interval\n        20, 0x00,                   // max interval\n        3, 0x00,                    // latency\n        (2 * 20 * 4) & 0xff, (2 * 20 * 4) >> 8, // timeout\n        0x00,                       // prefered periodicity (none)\n        0x00, 0x00,                 // ReferenceConnEventCount\n        0xff, 0xff,                 // Offset0 (none)\n        0xff, 0xff,                 // Offset1 (none)\n        0xff, 0xff,                 // Offset2 (none)\n        0xff, 0xff,                 // Offset3 (none)\n        0xff, 0xff,                 // Offset4 (none)\n        0xff, 0xff                  // Offset5 (none)\n    } );\n}\n\nBOOST_FIXTURE_TEST_CASE( if_central_protocol_version_is_40_use_l2cap, link_layer_with_signaling_channel )\n{\n    ll_control_pdu(\n        {\n            0x0C,               // LL_VERSION_IND\n            0x06,               // VersNr = Core Specification 4.0\n            0x00, 0x02,         // CompId\n            0x00, 0x00          // SubVersNr\n        } );\n\n    add_connection_event_respond(\n        [&](){\n            BOOST_REQUIRE( connection_parameter_update_request( 10, 20, 3, 2 * 20 * 4 ) );\n        });\n\n    ll_empty_pdus(3);\n\n    run( 5 );\n\n    check_outgoing_l2cap_pdu( {\n        X,  X, 0x05, 0x00, 0x12, X, 0x08, 0x00,\n        10, 0x00, 20, 0x00, 3, 0x00,\n        (2 * 20 * 4) & 0xff, (2 * 20 * 4) >> 8\n    } );\n}\n\nBOOST_FIXTURE_TEST_CASE( if_centrals_features_dont_contain_ll_use_l2cap, link_layer_with_signaling_channel )\n{\n    ll_control_pdu(\n        {\n            0x08,                    // LL_FEATURE_REQ\n            0x00, 0x00, 0x00, 0x00,  // no Connection Parameters Request Procedure\n            0x00, 0x00, 0x00, 0x00\n        } );\n\n    add_connection_event_respond(\n        [&](){\n            BOOST_REQUIRE( connection_parameter_update_request( 10, 20, 3, 2 * 20 * 4 ) );\n        });\n\n    ll_empty_pdus(3);\n\n    run( 5 );\n\n    check_outgoing_l2cap_pdu( {\n        X,  X, 0x05, 0x00, 0x12, X, 0x08, 0x00,\n        10, 0x00, 20, 0x00, 3, 0x00,\n        (2 * 20 * 4) & 0xff, (2 * 20 * 4) >> 8\n    } );\n}\n\nBOOST_FIXTURE_TEST_CASE( if_centrals_features_contain_ll_use_ll, link_layer_with_signaling_channel )\n{\n    ll_control_pdu(\n        {\n            0x08,                    // LL_FEATURE_REQ\n            0x02, 0x00, 0x00, 0x00,  // Connection Parameters Request Procedure\n            0x00, 0x00, 0x00, 0x00\n        } );\n\n    add_connection_event_respond(\n        [&](){\n            BOOST_REQUIRE( connection_parameter_update_request( 10, 20, 3, 2 * 20 * 4 ) );\n        });\n\n    ll_empty_pdus(3);\n\n    run( 5 );\n\n    check_outgoing_ll_control_pdu( {\n        0x0F,                       // LL_CONNECTION_PARAM_REQ\n        10, 0x00,                   // min interval\n        20, 0x00,                   // max interval\n        3, 0x00,                    // latency\n        (2 * 20 * 4) & 0xff, (2 * 20 * 4) >> 8, // timeout\n        0x00,                       // prefered periodicity (none)\n        0x00, 0x00,                 // ReferenceConnEventCount\n        0xff, 0xff,                 // Offset0 (none)\n        0xff, 0xff,                 // Offset1 (none)\n        0xff, 0xff,                 // Offset2 (none)\n        0xff, 0xff,                 // Offset3 (none)\n        0xff, 0xff,                 // Offset4 (none)\n        0xff, 0xff                  // Offset5 (none)\n    } );\n}\n\nBOOST_FIXTURE_TEST_CASE( if_ll_doesn_work_fallback_to_l2cap, link_layer_with_signaling_channel )\n{\n    ll_function_call(\n        [&](){\n            BOOST_REQUIRE( connection_parameter_update_request( 10, 20, 3, 2 * 20 * 4 ) );\n        });\n\n    ll_empty_pdus(3);\n\n    ll_control_pdu( {\n        0x07,                       // LL_UNKNOWN_RSP\n        0x0F                        // LL_CONNECTION_PARAM_REQ\n    } );\n\n    ll_empty_pdus(3);\n\n    run( 5 );\n\n    // first tried with LL_CONNECTION_PARAM_REQ\n    check_outgoing_ll_control_pdu( {\n        0x0F,                       // LL_CONNECTION_PARAM_REQ\n        10, 0x00,                   // min interval\n        20, 0x00,                   // max interval\n        3, 0x00,                    // latency\n        (2 * 20 * 4) & 0xff, (2 * 20 * 4) >> 8, // timeout\n        0x00,                       // prefered periodicity (none)\n        0x00, 0x00,                 // ReferenceConnEventCount\n        0xff, 0xff,                 // Offset0 (none)\n        0xff, 0xff,                 // Offset1 (none)\n        0xff, 0xff,                 // Offset2 (none)\n        0xff, 0xff,                 // Offset3 (none)\n        0xff, 0xff,                 // Offset4 (none)\n        0xff, 0xff                  // Offset5 (none)\n    } );\n\n    // as fallback, try l2cap\n    check_outgoing_l2cap_pdu( {\n        X,  X, 0x05, 0x00, 0x12, X, 0x08, 0x00,\n        10, 0x00, 20, 0x00, 3, 0x00,\n        (2 * 20 * 4) & 0xff, (2 * 20 * 4) >> 8\n    } );\n}\n\nBOOST_FIXTURE_TEST_CASE( if_ll_was_rejected_fallback_to_l2cap, link_layer_with_signaling_channel )\n{\n    ll_function_call(\n        [&](){\n            BOOST_REQUIRE( connection_parameter_update_request( 10, 20, 3, 2 * 20 * 4 ) );\n        });\n\n    ll_empty_pdus(3);\n\n    ll_control_pdu( {\n        0x0D,                       // LL_REJECT_IND\n        0x1A                        // Unsupported Remote/LMP Feature (0x1a)\n    } );\n\n    ll_empty_pdus(3);\n\n    run( 5 );\n\n    // first tried with LL_CONNECTION_PARAM_REQ\n    check_outgoing_ll_control_pdu( {\n        0x0F,                       // LL_CONNECTION_PARAM_REQ\n        10, 0x00,                   // min interval\n        20, 0x00,                   // max interval\n        3, 0x00,                    // latency\n        (2 * 20 * 4) & 0xff, (2 * 20 * 4) >> 8, // timeout\n        0x00,                       // prefered periodicity (none)\n        0x00, 0x00,                 // ReferenceConnEventCount\n        0xff, 0xff,                 // Offset0 (none)\n        0xff, 0xff,                 // Offset1 (none)\n        0xff, 0xff,                 // Offset2 (none)\n        0xff, 0xff,                 // Offset3 (none)\n        0xff, 0xff,                 // Offset4 (none)\n        0xff, 0xff                  // Offset5 (none)\n    } );\n\n    // as fallback, try l2cap\n    check_outgoing_l2cap_pdu( {\n        X,  X, 0x05, 0x00, 0x12, X, 0x08, 0x00,\n        10, 0x00, 20, 0x00, 3, 0x00,\n        (2 * 20 * 4) & 0xff, (2 * 20 * 4) >> 8\n    } );\n}\n\nBOOST_FIXTURE_TEST_CASE( if_ll_was_rejected_ext_fallback_to_l2cap, link_layer_with_signaling_channel )\n{\n    ll_function_call(\n        [&](){\n            BOOST_REQUIRE( connection_parameter_update_request( 10, 20, 3, 2 * 20 * 4 ) );\n        });\n\n    ll_empty_pdus(3);\n\n    ll_control_pdu( {\n        0x11,                       // LL_REJECT_IND_EXT\n        0x0F,                       // opcde\n        0x1A                        // Unsupported Remote/LMP Feature (0x1a)\n    } );\n\n    ll_empty_pdus(3);\n\n    run( 5 );\n\n    // first tried with LL_CONNECTION_PARAM_REQ\n    check_outgoing_ll_control_pdu( {\n        0x0F,                       // LL_CONNECTION_PARAM_REQ\n        10, 0x00,                   // min interval\n        20, 0x00,                   // max interval\n        3, 0x00,                    // latency\n        (2 * 20 * 4) & 0xff, (2 * 20 * 4) >> 8, // timeout\n        0x00,                       // prefered periodicity (none)\n        0x00, 0x00,                 // ReferenceConnEventCount\n        0xff, 0xff,                 // Offset0 (none)\n        0xff, 0xff,                 // Offset1 (none)\n        0xff, 0xff,                 // Offset2 (none)\n        0xff, 0xff,                 // Offset3 (none)\n        0xff, 0xff,                 // Offset4 (none)\n        0xff, 0xff                  // Offset5 (none)\n    } );\n\n    // as fallback, try l2cap\n    check_outgoing_l2cap_pdu( {\n        X,  X, 0x05, 0x00, 0x12, X, 0x08, 0x00,\n        10, 0x00, 20, 0x00, 3, 0x00,\n        (2 * 20 * 4) & 0xff, (2 * 20 * 4) >> 8\n    } );\n}\n\nBOOST_FIXTURE_TEST_CASE( copy_data_from_request, link_layer_with_signaling_channel )\n{\n    ll_control_pdu( {\n        0x0F,                       // LL_CONNECTION_PARAM_REQ\n        10, 0x00,                   // min interval\n        20, 0x00,                   // max interval\n        3, 0x00,                    // latency\n        (2 * 20 * 4) & 0xff, (2 * 20 * 4) >> 8, // timeout\n        0x00,                       // prefered periodicity (none)\n        0x00, 0x00,                 // ReferenceConnEventCount\n        0x02, 0x00,                 // Offset0 (none)\n        0x04, 0x00,                 // Offset1 (none)\n        0xff, 0xff,                 // Offset2 (none)\n        0xff, 0xff,                 // Offset3 (none)\n        0xff, 0xff,                 // Offset4 (none)\n        0xff, 0xff                  // Offset5 (none)\n    } );\n\n    ll_empty_pdus(3);\n\n    run( 5 );\n\n    check_outgoing_ll_control_pdu( {\n        0x10,                       // LL_CONNECTION_PARAM_RSP\n        10, 0x00,                   // min interval\n        20, 0x00,                   // max interval\n        3, 0x00,                    // latency\n        (2 * 20 * 4) & 0xff, (2 * 20 * 4) >> 8, // timeout\n        0x00,                       // prefered periodicity (none)\n        0x00, 0x00,                 // ReferenceConnEventCount\n        0x02, 0x00,                 // Offset0 (none)\n        0x04, 0x00,                 // Offset1 (none)\n        0xff, 0xff,                 // Offset2 (none)\n        0xff, 0xff,                 // Offset3 (none)\n        0xff, 0xff,                 // Offset4 (none)\n        0xff, 0xff                  // Offset5 (none)\n    } );\n}\n\nusing desired_connection_parameters = bluetoe::link_layer::desired_connection_parameters<\n    11, 19,\n    2, 20,\n    1*20*4, 2*20*4\n>;\n\nstruct link_layer_with_desired_connection_parameters : unconnected_base< bluetoe::l2cap::signaling_channel<>, test::buffer_sizes, desired_connection_parameters >\n{\n    link_layer_with_desired_connection_parameters()\n    {\n        respond_to( 37, valid_connection_request_pdu );\n    }\n};\n\nBOOST_FIXTURE_TEST_CASE( respond_with_desired_parameters, link_layer_with_desired_connection_parameters )\n{\n    ll_control_pdu( {\n        0x0F,                       // LL_CONNECTION_PARAM_REQ\n        10, 0x00,                   // min interval\n        20, 0x00,                   // max interval\n        3, 0x00,                    // latency\n        (2 * 20 * 4) & 0xff, (2 * 20 * 4) >> 8, // timeout\n        0x00,                       // prefered periodicity (none)\n        0x00, 0x00,                 // ReferenceConnEventCount\n        0x02, 0x00,                 // Offset0 (none)\n        0x04, 0x00,                 // Offset1 (none)\n        0xff, 0xff,                 // Offset2 (none)\n        0xff, 0xff,                 // Offset3 (none)\n        0xff, 0xff,                 // Offset4 (none)\n        0xff, 0xff                  // Offset5 (none)\n    } );\n\n    ll_empty_pdus(3);\n\n    run( 5 );\n\n    check_outgoing_ll_control_pdu( {\n        0x10,                       // LL_CONNECTION_PARAM_RSP\n        11, 0x00,                   // min interval\n        19, 0x00,                   // max interval\n        3, 0x00,                    // latency\n        (2 * 20 * 4) & 0xff, (2 * 20 * 4) >> 8, // timeout\n        0x00,                       // prefered periodicity (none)\n        0x00, 0x00,                 // ReferenceConnEventCount\n        0x02, 0x00,                 // Offset0 (none)\n        0x04, 0x00,                 // Offset1 (none)\n        0xff, 0xff,                 // Offset2 (none)\n        0xff, 0xff,                 // Offset3 (none)\n        0xff, 0xff,                 // Offset4 (none)\n        0xff, 0xff                  // Offset5 (none)\n    } );\n}\n\nBOOST_FIXTURE_TEST_CASE( requested_interval_outside_of_desired_values, link_layer_with_desired_connection_parameters )\n{\n    ll_control_pdu( {\n        0x0F,                       // LL_CONNECTION_PARAM_REQ\n        20, 0x00,                   // min interval\n        30, 0x00,                   // max interval\n        3, 0x00,                    // latency\n        (2 * 20 * 4) & 0xff, (2 * 20 * 4) >> 8, // timeout\n        0x00,                       // prefered periodicity (none)\n        0x00, 0x00,                 // ReferenceConnEventCount\n        0x02, 0x00,                 // Offset0 (none)\n        0x04, 0x00,                 // Offset1 (none)\n        0xff, 0xff,                 // Offset2 (none)\n        0xff, 0xff,                 // Offset3 (none)\n        0xff, 0xff,                 // Offset4 (none)\n        0xff, 0xff                  // Offset5 (none)\n    } );\n\n    ll_empty_pdus(3);\n\n    run( 5 );\n\n    check_outgoing_ll_control_pdu( {\n        0x10,                       // LL_CONNECTION_PARAM_RSP\n        11, 0x00,                   // min interval\n        19, 0x00,                   // max interval\n        3, 0x00,                    // latency\n        (2 * 20 * 4) & 0xff, (2 * 20 * 4) >> 8, // timeout\n        0x00,                       // prefered periodicity (none)\n        0x00, 0x00,                 // ReferenceConnEventCount\n        0x02, 0x00,                 // Offset0 (none)\n        0x04, 0x00,                 // Offset1 (none)\n        0xff, 0xff,                 // Offset2 (none)\n        0xff, 0xff,                 // Offset3 (none)\n        0xff, 0xff,                 // Offset4 (none)\n        0xff, 0xff                  // Offset5 (none)\n    } );\n}\n\nBOOST_FIXTURE_TEST_CASE( requested_latency_outside_of_desired_values, link_layer_with_desired_connection_parameters )\n{\n    ll_control_pdu( {\n        0x0F,                       // LL_CONNECTION_PARAM_REQ\n        10, 0x00,                   // min interval\n        20, 0x00,                   // max interval\n        0, 0x00,                    // latency\n        (2 * 20 * 4) & 0xff, (2 * 20 * 4) >> 8, // timeout\n        0x00,                       // prefered periodicity (none)\n        0x00, 0x00,                 // ReferenceConnEventCount\n        0x02, 0x00,                 // Offset0 (none)\n        0x04, 0x00,                 // Offset1 (none)\n        0xff, 0xff,                 // Offset2 (none)\n        0xff, 0xff,                 // Offset3 (none)\n        0xff, 0xff,                 // Offset4 (none)\n        0xff, 0xff                  // Offset5 (none)\n    } );\n\n    ll_empty_pdus(3);\n\n    run( 5 );\n\n    check_outgoing_ll_control_pdu( {\n        0x10,                       // LL_CONNECTION_PARAM_RSP\n        11, 0x00,                   // min interval\n        19, 0x00,                   // max interval\n        11, 0x00,                   // latency\n        (2 * 20 * 4) & 0xff, (2 * 20 * 4) >> 8, // timeout\n        0x00,                       // prefered periodicity (none)\n        0x00, 0x00,                 // ReferenceConnEventCount\n        0x02, 0x00,                 // Offset0 (none)\n        0x04, 0x00,                 // Offset1 (none)\n        0xff, 0xff,                 // Offset2 (none)\n        0xff, 0xff,                 // Offset3 (none)\n        0xff, 0xff,                 // Offset4 (none)\n        0xff, 0xff                  // Offset5 (none)\n    } );\n}\n\nBOOST_FIXTURE_TEST_CASE( requested_timeout_outside_of_desired_values, link_layer_with_desired_connection_parameters )\n{\n    ll_control_pdu( {\n        0x0F,                       // LL_CONNECTION_PARAM_REQ\n        10, 0x00,                   // min interval\n        20, 0x00,                   // max interval\n        3, 0x00,                    // latency\n        (3 * 20 * 4) & 0xff, (4 * 20 * 4) >> 8, // timeout\n        0x00,                       // prefered periodicity (none)\n        0x00, 0x00,                 // ReferenceConnEventCount\n        0x02, 0x00,                 // Offset0 (none)\n        0x04, 0x00,                 // Offset1 (none)\n        0xff, 0xff,                 // Offset2 (none)\n        0xff, 0xff,                 // Offset3 (none)\n        0xff, 0xff,                 // Offset4 (none)\n        0xff, 0xff                  // Offset5 (none)\n    } );\n\n    ll_empty_pdus(3);\n\n    run( 5 );\n\n    check_outgoing_ll_control_pdu( {\n        0x10,                       // LL_CONNECTION_PARAM_RSP\n        11, 0x00,                   // min interval\n        19, 0x00,                   // max interval\n        3, 0x00,                    // latency\n        120 & 0xff, 120 >> 8, // timeout\n        0x00,                       // prefered periodicity (none)\n        0x00, 0x00,                 // ReferenceConnEventCount\n        0x02, 0x00,                 // Offset0 (none)\n        0x04, 0x00,                 // Offset1 (none)\n        0xff, 0xff,                 // Offset2 (none)\n        0xff, 0xff,                 // Offset3 (none)\n        0xff, 0xff,                 // Offset4 (none)\n        0xff, 0xff                  // Offset5 (none)\n    } );\n}\n\nstruct connection_parameter_update_cb_t\n{\npublic:\n    connection_parameter_update_cb_t()\n        : remote_connection_parameter_request_received( false )\n    {\n    }\n\n    void ll_remote_connection_parameter_request(\n        std::uint16_t interval_min,\n        std::uint16_t interval_max,\n        std::uint16_t latency,\n        std::uint16_t timeout )\n    {\n        remote_connection_parameter_request_received = true;\n\n        requested_interval_min  = interval_min;\n        requested_interval_max  = interval_max;\n        requested_latency       = latency;\n        requested_timeout       = timeout;\n    }\n\n    bool remote_connection_parameter_request_received;\n    std::uint16_t requested_interval_min;\n    std::uint16_t requested_interval_max;\n    std::uint16_t requested_latency;\n    std::uint16_t requested_timeout;\n\n} connection_parameter_update_cb;\n\nstruct link_layer_with_async_parameters : unconnected_base<\n    bluetoe::l2cap::signaling_channel<>,\n    test::buffer_sizes,\n    bluetoe::link_layer::asynchronous_connection_parameter_request< connection_parameter_update_cb_t, connection_parameter_update_cb > >\n{\n    link_layer_with_async_parameters()\n    {\n        connection_parameter_update_cb = connection_parameter_update_cb_t();\n        respond_to( 37, valid_connection_request_pdu );\n    }\n};\n\nusing connection_parameters_configurations = std::tuple<\n    link_layer_with_desired_connection_parameters,\n    link_layer_with_signaling_channel,\n    link_layer_with_async_parameters >;\n\n/**\n * LL/CON/PER/BI-16-C\n */\nBOOST_AUTO_TEST_CASE_TEMPLATE( Reject_Invalid_Connection_Parameter_Request_Parameters, fixture_t, connection_parameters_configurations )\n{\n    fixture_t link_layer;\n\n    link_layer.ll_control_pdu( {\n        0x0F,                       // LL_CONNECTION_PARAM_REQ\n        20, 0x00,                   // min interval\n        10, 0x00,                   // max interval\n        3, 0x00,                    // latency\n        (3 * 20 * 4) & 0xff, (4 * 20 * 4) >> 8, // timeout\n        0x00,                       // prefered periodicity (none)\n        0xff, 0xff,                 // ReferenceConnEventCount\n        0xff, 0xff,                 // Offset0 (none)\n        0xff, 0xff,                 // Offset1 (none)\n        0xff, 0xff,                 // Offset2 (none)\n        0xff, 0xff,                 // Offset3 (none)\n        0xff, 0xff,                 // Offset4 (none)\n        0xff, 0xff                  // Offset5 (none)\n    } );\n\n    link_layer.ll_empty_pdus(3);\n\n    link_layer.run( 5 );\n\n    link_layer.check_outgoing_ll_control_pdu( {\n        0x11,                       // LL_REJECT_EXT_IND\n        0x0F,                       // LL_CONNECTION_PARAM_REQ\n        0x1E                        // ErrorCode\n    } );\n}\n\n/**\n * LL/CON/PER/BI-08-C I\n */\nBOOST_AUTO_TEST_CASE_TEMPLATE( Accepting_Connection_Parameter_Request__illegal_parameters_I, fixture_t, connection_parameters_configurations )\n{\n    fixture_t link_layer;\n\n    link_layer.ll_control_pdu( {\n        0x0F,                       // LL_CONNECTION_PARAM_REQ\n        4, 0x00,                    // min interval\n        10, 0x00,                   // max interval\n        3, 0x00,                    // latency\n        (3 * 20 * 4) & 0xff, (4 * 20 * 4) >> 8, // timeout\n        0x00,                       // prefered periodicity (none)\n        0xff, 0xff,                 // ReferenceConnEventCount\n        0xff, 0xff,                 // Offset0 (none)\n        0xff, 0xff,                 // Offset1 (none)\n        0xff, 0xff,                 // Offset2 (none)\n        0xff, 0xff,                 // Offset3 (none)\n        0xff, 0xff,                 // Offset4 (none)\n        0xff, 0xff                  // Offset5 (none)\n    } );\n\n    link_layer.ll_empty_pdus(3);\n\n    link_layer.run( 5 );\n\n    link_layer.check_outgoing_ll_control_pdu( {\n        0x11,                       // LL_REJECT_EXT_IND\n        0x0F,                       // LL_CONNECTION_PARAM_REQ\n        0x1E                        // ErrorCode\n    } );\n}\n\n/**\n * LL/CON/PER/BI-08-C II\n */\nBOOST_AUTO_TEST_CASE_TEMPLATE( Accepting_Connection_Parameter_Request__illegal_parameters_II, fixture_t, connection_parameters_configurations )\n{\n    fixture_t link_layer;\n\n    link_layer.ll_control_pdu( {\n        0x0F,                       // LL_CONNECTION_PARAM_REQ\n        5, 0x00,                    // min interval\n        0x81, 0x0C,                 // max interval\n        3, 0x00,                    // latency\n        (3 * 20 * 4) & 0xff, (4 * 20 * 4) >> 8, // timeout\n        0x00,                       // prefered periodicity (none)\n        0xff, 0xff,                 // ReferenceConnEventCount\n        0xff, 0xff,                 // Offset0 (none)\n        0xff, 0xff,                 // Offset1 (none)\n        0xff, 0xff,                 // Offset2 (none)\n        0xff, 0xff,                 // Offset3 (none)\n        0xff, 0xff,                 // Offset4 (none)\n        0xff, 0xff                  // Offset5 (none)\n    } );\n\n    link_layer.ll_empty_pdus(3);\n\n    link_layer.run( 5 );\n\n    link_layer.check_outgoing_ll_control_pdu( {\n        0x11,                       // LL_REJECT_EXT_IND\n        0x0F,                       // LL_CONNECTION_PARAM_REQ\n        0x1E                        // ErrorCode\n    } );\n}\n\n/**\n * LL/CON/PER/BI-08-C III\n */\nBOOST_AUTO_TEST_CASE_TEMPLATE( Accepting_Connection_Parameter_Request__illegal_parameters_III, fixture_t, connection_parameters_configurations )\n{\n    fixture_t link_layer;\n\n    link_layer.ll_control_pdu( {\n        0x0F,                       // LL_CONNECTION_PARAM_REQ\n        5, 0x00,                    // min interval\n        10, 0x00,                   // max interval\n        0xf4, 0x01,                 // latency 500\n        (3 * 20 * 4) & 0xff, (4 * 20 * 4) >> 8, // timeout\n        0x00,                       // prefered periodicity (none)\n        0xff, 0xff,                 // ReferenceConnEventCount\n        0xff, 0xff,                 // Offset0 (none)\n        0xff, 0xff,                 // Offset1 (none)\n        0xff, 0xff,                 // Offset2 (none)\n        0xff, 0xff,                 // Offset3 (none)\n        0xff, 0xff,                 // Offset4 (none)\n        0xff, 0xff                  // Offset5 (none)\n    } );\n\n    link_layer.ll_empty_pdus(3);\n\n    link_layer.run( 5 );\n\n    link_layer.check_outgoing_ll_control_pdu( {\n        0x11,                       // LL_REJECT_EXT_IND\n        0x0F,                       // LL_CONNECTION_PARAM_REQ\n        0x1E                        // ErrorCode\n    } );\n}\n\nBOOST_FIXTURE_TEST_CASE( requesting_connect_parameters_parameters_test, link_layer_with_async_parameters )\n{\n    ll_control_pdu( {\n        0x0F,                       // LL_CONNECTION_PARAM_REQ\n        10, 0x00,                   // min interval\n        20, 0x00,                   // max interval\n        5, 0x00,                    // latency\n        (2 * 20 * 4) & 0xff, (2 * 20 * 4) >> 8, // timeout\n        0x00,                       // prefered periodicity (none)\n        0x00, 0x00,                 // ReferenceConnEventCount\n        0x02, 0x00,                 // Offset0 (none)\n        0x04, 0x00,                 // Offset1 (none)\n        0xff, 0xff,                 // Offset2 (none)\n        0xff, 0xff,                 // Offset3 (none)\n        0xff, 0xff,                 // Offset4 (none)\n        0xff, 0xff                  // Offset5 (none)\n    } );\n\n    ll_empty_pdus(3);\n\n    run( 5 );\n\n    check_connection_events( [&]( const test::connection_event& evt ) -> bool {\n        using test::X;\n        using test::and_so_on;\n\n        for ( const auto& response: evt.transmitted_data )\n        {\n            if ( check_pdu( response, { X, X, 0x11, and_so_on } )\n              || check_pdu( response, { X, X, 0x10, and_so_on } ) )\n                return false;\n        }\n\n        return true;\n    }, \"no LL_REJECT_EXT_IND and no LL_CONNECTION_PARAM_RSP\" );\n\n    BOOST_REQUIRE( connection_parameter_update_cb.remote_connection_parameter_request_received );\n    BOOST_CHECK_EQUAL( connection_parameter_update_cb.requested_interval_min, 10 );\n    BOOST_CHECK_EQUAL( connection_parameter_update_cb.requested_interval_max, 20 );\n    BOOST_CHECK_EQUAL( connection_parameter_update_cb.requested_latency, 5 );\n    BOOST_CHECK_EQUAL( connection_parameter_update_cb.requested_timeout, 2 * 20 * 4 );\n}\n\nBOOST_FIXTURE_TEST_CASE( requesting_connect_parameters_reply_test, link_layer_with_async_parameters )\n{\n    ll_control_pdu( {\n        0x0F,                       // LL_CONNECTION_PARAM_REQ\n        10, 0x00,                   // min interval\n        20, 0x00,                   // max interval\n        5, 0x00,                    // latency\n        (2 * 20 * 4) & 0xff, (2 * 20 * 4) >> 8, // timeout\n        0x00,                       // prefered periodicity (none)\n        0x00, 0x00,                 // ReferenceConnEventCount\n        0x02, 0x00,                 // Offset0 (none)\n        0x04, 0x00,                 // Offset1 (none)\n        0xff, 0xff,                 // Offset2 (none)\n        0xff, 0xff,                 // Offset3 (none)\n        0xff, 0xff,                 // Offset4 (none)\n        0xff, 0xff                  // Offset5 (none)\n    } );\n    ll_empty_pdus(3);\n    ll_function_call([this](){\n        connection_parameters_request_reply( 11, 19, 3, 2 * 20 * 4 - 5 );\n    });\n    ll_empty_pdus(3);\n\n    run( 5 );\n\n    check_outgoing_ll_control_pdu( {\n        0x10,                       // LL_CONNECTION_PARAM_RSP\n        11, 0x00,                   // min interval\n        19, 0x00,                   // max interval\n        3, 0x00,                    // latency\n        (2 * 20 * 4 - 5) & 0xff, (2 * 20 * 4 - 5) >> 8, // timeout\n        0x00,                       // prefered periodicity (none)\n        0xff, 0xff,                 // ReferenceConnEventCount\n        0xff, 0xff,                 // Offset0 (none)\n        0xff, 0xff,                 // Offset1 (none)\n        0xff, 0xff,                 // Offset2 (none)\n        0xff, 0xff,                 // Offset3 (none)\n        0xff, 0xff,                 // Offset4 (none)\n        0xff, 0xff                  // Offset5 (none)\n    } );\n}\n\nBOOST_FIXTURE_TEST_CASE( requesting_connect_parameters_negative_reply_test, link_layer_with_async_parameters )\n{\n    ll_control_pdu( {\n        0x0F,                       // LL_CONNECTION_PARAM_REQ\n        10, 0x00,                   // min interval\n        20, 0x00,                   // max interval\n        5, 0x00,                    // latency\n        (2 * 20 * 4) & 0xff, (2 * 20 * 4) >> 8, // timeout\n        0x00,                       // prefered periodicity (none)\n        0x00, 0x00,                 // ReferenceConnEventCount\n        0x02, 0x00,                 // Offset0 (none)\n        0x04, 0x00,                 // Offset1 (none)\n        0xff, 0xff,                 // Offset2 (none)\n        0xff, 0xff,                 // Offset3 (none)\n        0xff, 0xff,                 // Offset4 (none)\n        0xff, 0xff                  // Offset5 (none)\n    } );\n    ll_empty_pdus(3);\n    ll_function_call([this](){\n        connection_parameters_request_negative_reply(0x3B);\n    });\n    ll_empty_pdus(3);\n\n    run( 5 );\n\n    check_outgoing_ll_control_pdu( {\n        0x11,                       // LL_REJECT_EXT_IND\n        0x0F,                       // LL_CONNECTION_PARAM_REQ\n        0x3B                        // UNACCEPTABLE CONNECTION PARAMETERS\n    } );\n}\n\n/**\n * LL/CON/PER/BV-30-C\n */\nBOOST_FIXTURE_TEST_CASE( Accepting_Connection_Parameter_Request__preferred_anchor_points_only, link_layer_with_async_parameters )\n{\n    ll_control_pdu( {\n        0x0F,                       // LL_CONNECTION_PARAM_REQ\n        0x18, 0x00,                 // min interval (30ms)\n        0x18, 0x00,                 // max interval (30ms)\n        0x00, 0x00,                 // latency latency\n        0x48, 0x00,                 // connection timeout (720ms)\n        0x00,                       // prefered periodicity (none)\n        0x20, 0x00,                 // ReferenceConnEventCount\n        0x02, 0x00,                 // Offset0 (none)\n        0xff, 0xff,                 // Offset1 (none)\n        0xff, 0xff,                 // Offset2 (none)\n        0xff, 0xff,                 // Offset3 (none)\n        0xff, 0xff,                 // Offset4 (none)\n        0xff, 0xff                  // Offset5 (none)\n    } );\n    ll_empty_pdus(3);\n\n    run( 5 );\n\n    check_outgoing_ll_control_pdu( {\n        0x10,                       // LL_CONNECTION_PARAM_RSP\n        0x18, 0x00,                 // min interval (30ms)\n        0x18, 0x00,                 // max interval (30ms)\n        0x00, 0x00,                 // latency latency\n        0x48, 0x00,                 // connection timeout (720ms)\n        0x00,                       // prefered periodicity (none)\n        0x20, 0x00,                 // ReferenceConnEventCount\n        0x02, 0x00,                 // Offset0 (none)\n        0xff, 0xff,                 // Offset1 (none)\n        0xff, 0xff,                 // Offset2 (none)\n        0xff, 0xff,                 // Offset3 (none)\n        0xff, 0xff,                 // Offset4 (none)\n        0xff, 0xff                  // Offset5 (none)\n    } );\n\n    BOOST_REQUIRE( !connection_parameter_update_cb.remote_connection_parameter_request_received );\n}\n\n/**\n * LL/CON/PER/BV-31-C\n * LL/CON/PER/BV-32-C\n */\nBOOST_FIXTURE_TEST_CASE( Accepting_Connection_Parameter_Request__Interval_Range_Not_Zero, link_layer_with_async_parameters )\n{\n    ll_control_pdu( {\n        0x0F,                       // LL_CONNECTION_PARAM_REQ\n        0x18, 0x00,                 // min interval (30ms)\n        0x30, 0x00,                 // max interval (60ms)\n        0x00, 0x00,                 // latency latency\n        0x48, 0x00,                 // connection timeout (720ms)\n        0x08,                       // prefered periodicity (10ms)\n        0xff, 0xff,                 // ReferenceConnEventCount\n        0xff, 0xff,                 // Offset0 (none)\n        0xff, 0xff,                 // Offset1 (none)\n        0xff, 0xff,                 // Offset2 (none)\n        0xff, 0xff,                 // Offset3 (none)\n        0xff, 0xff,                 // Offset4 (none)\n        0xff, 0xff                  // Offset5 (none)\n    } );\n    ll_empty_pdus(3);\n\n    run( 5 );\n\n    // in this case, the upcall to the host is required\n    BOOST_REQUIRE( connection_parameter_update_cb.remote_connection_parameter_request_received );\n}\n"
  },
  {
    "path": "tests/link_layer/delta_time_tests.cpp",
    "content": "#include <bluetoe/delta_time.hpp>\n\n#define BOOST_TEST_MODULE\n#include <boost/test/included/unit_test.hpp>\n#include <algorithm>\n\nnamespace bll = bluetoe::link_layer;\n\nBOOST_FIXTURE_TEST_CASE( is_default_constructable, bluetoe::link_layer::delta_time )\n{\n    BOOST_CHECK_EQUAL( usec(), 0u );\n    BOOST_CHECK_EQUAL( bluetoe::link_layer::delta_time::now().usec(), 0u );\n}\n\nBOOST_AUTO_TEST_CASE( constructable_from_number_of_micro_seconds )\n{\n    BOOST_CHECK_EQUAL( bluetoe::link_layer::delta_time( 4711 ).usec(), 4711u );\n    BOOST_CHECK_EQUAL( bluetoe::link_layer::delta_time::usec( 4711 ).usec(), 4711u );\n}\n\nBOOST_AUTO_TEST_CASE( constructable_from_number_of_milli_seconds )\n{\n    BOOST_CHECK_EQUAL( bluetoe::link_layer::delta_time::msec( 4711 ).usec(), 4711000u );\n}\n\nBOOST_AUTO_TEST_CASE( constructable_from_number_of_seconds )\n{\n    BOOST_CHECK_EQUAL( bluetoe::link_layer::delta_time::seconds( 11 ).usec(), 11000000u );\n}\n\nBOOST_AUTO_TEST_CASE( provides_equal_comparison )\n{\n    BOOST_CHECK( bll::delta_time::usec( 5000 ) == bll::delta_time::msec( 5 ) );\n    BOOST_CHECK( !( bll::delta_time::usec( 5000 ) == bll::delta_time::usec( 5001 ) ) );\n}\n\nBOOST_AUTO_TEST_CASE( provides_inequal_comparison )\n{\n    BOOST_CHECK( !( bll::delta_time::usec( 5000 ) != bll::delta_time::msec( 5 ) ) );\n    BOOST_CHECK( bll::delta_time::usec( 5000 ) != bll::delta_time::usec( 5001 ) );\n}\n\nBOOST_AUTO_TEST_CASE( provides_less_than_comparison )\n{\n    BOOST_CHECK( bll::delta_time::usec( 5000 ) < bll::delta_time::usec( 5001 ) );\n    BOOST_CHECK( !( bll::delta_time::usec( 5000 ) < bll::delta_time::usec( 5000 ) ) );\n    BOOST_CHECK( !( bll::delta_time::usec( 5000 ) < bll::delta_time::usec( 4999 ) ) );\n}\n\nBOOST_AUTO_TEST_CASE( provides_greater_than_comparison )\n{\n    BOOST_CHECK( bll::delta_time::usec( 5000 ) > bll::delta_time::usec( 4999 ) );\n    BOOST_CHECK( !( bll::delta_time::usec( 5000 ) > bll::delta_time::usec( 5000 ) ) );\n    BOOST_CHECK( !( bll::delta_time::usec( 5000 ) > bll::delta_time::usec( 5001 ) ) );\n}\n\nBOOST_AUTO_TEST_CASE( provides_less_than_or_equal_comparison )\n{\n    BOOST_CHECK( bll::delta_time::usec( 5000 ) <= bll::delta_time::usec( 5001 ) );\n    BOOST_CHECK( bll::delta_time::usec( 5000 ) <= bll::delta_time::usec( 5000 ) );\n    BOOST_CHECK( !( bll::delta_time::usec( 5000 ) <= bll::delta_time::usec( 4999 ) ) );\n}\n\nBOOST_AUTO_TEST_CASE( provides_greater_than_or_equal_comparison )\n{\n    BOOST_CHECK( bll::delta_time::usec( 5000 ) >= bll::delta_time::usec( 4999 ) );\n    BOOST_CHECK( bll::delta_time::usec( 5000 ) >= bll::delta_time::usec( 5000 ) );\n    BOOST_CHECK( !( bll::delta_time::usec( 5000 ) >= bll::delta_time::usec( 5001 ) ) );\n}\n\nBOOST_AUTO_TEST_CASE( provides_a_zero_check )\n{\n    BOOST_CHECK( bll::delta_time::now().zero() );\n    BOOST_CHECK( !bll::delta_time::usec( 5000 ).zero() );\n}\n\nBOOST_AUTO_TEST_CASE( multiplication_with_zero )\n{\n    bll::delta_time z( 0 );\n    bll::delta_time o( 1 );\n    bll::delta_time h( 100 );\n\n    z *= 0;\n    o *= 0;\n    h *= 0;\n\n    BOOST_CHECK_EQUAL( z, bll::delta_time::now() );\n    BOOST_CHECK_EQUAL( o, bll::delta_time::now() );\n    BOOST_CHECK_EQUAL( h, bll::delta_time::now() );\n}\n\nBOOST_AUTO_TEST_CASE( multiplication_with_one )\n{\n    bll::delta_time z( 0 );\n    bll::delta_time o( 1 );\n    bll::delta_time h( 100 );\n\n    z *= 1;\n    o *= 1;\n    h *= 1;\n\n    BOOST_CHECK_EQUAL( z, bll::delta_time( 0 ) );\n    BOOST_CHECK_EQUAL( o, bll::delta_time( 1 ) );\n    BOOST_CHECK_EQUAL( h, bll::delta_time( 100 ) );\n}\n\nBOOST_AUTO_TEST_CASE( multiplication_with_greater_than_1 )\n{\n    bll::delta_time z( 0 );\n    bll::delta_time o( 1 );\n    bll::delta_time h( 100 );\n\n    z *= 5;\n    o *= 5;\n    h *= 5;\n\n    BOOST_CHECK_EQUAL( z, bll::delta_time( 0 ) );\n    BOOST_CHECK_EQUAL( o, bll::delta_time( 5 ) );\n    BOOST_CHECK_EQUAL( h, bll::delta_time( 500 ) );\n}\n\nBOOST_AUTO_TEST_CASE( binary_multiplication_operators )\n{\n    BOOST_CHECK_EQUAL( bll::delta_time( 5 ) * 5, bll::delta_time( 25 ) );\n    BOOST_CHECK_EQUAL( 5 * bll::delta_time( 5 ), bll::delta_time( 25 ) );\n}\n\nBOOST_AUTO_TEST_CASE( division_by_delta_time )\n{\n    bll::delta_time h( 100 );\n    bll::delta_time z( 20 );\n    bll::delta_time s( 1000 );\n\n    BOOST_CHECK_EQUAL( h / z, 5u );\n    BOOST_CHECK_EQUAL( h / s, 0u );\n    BOOST_CHECK_EQUAL( h / h, 1u );\n}\n\nBOOST_AUTO_TEST_SUITE( Abort_Operation_Procedure )\n\nstatic constexpr long required_accuary = 1000000;\n\nstatic void check_close( const bll::delta_time& result, std::uint32_t expected )\n{\n    const std::uint32_t tolerance = std::max< std::uint32_t >( 1, expected / required_accuary );\n\n    BOOST_CHECK_GE(\n        static_cast< std::int64_t >( result.usec() ),\n        std::int64_t( expected ) - tolerance );\n\n    BOOST_CHECK_LE(\n        static_cast< std::int64_t >( result.usec() ),\n        std::int64_t( expected ) + tolerance );\n}\n\nBOOST_AUTO_TEST_CASE( can_calculate_part_per_million )\n{\n    check_close( bll::delta_time::usec( 5000 ).ppm( 1000 ), 5 );\n}\n\nBOOST_AUTO_TEST_CASE( ppm_with_calculations_that_should_overflow_32bit_math )\n{\n    check_close(\n        bll::delta_time::usec( 100 * 1000 * 1000 ).ppm( 1000 ),\n        100 * 1000 );\n}\n\nBOOST_AUTO_TEST_CASE( ppm_with_some_extrem_values )\n{\n    check_close( bll::delta_time::usec( 1000 * 1000 * 1000 ).ppm( 0 ), 0 );\n    check_close( bll::delta_time::usec( 1000 * 1000 * 1000 ).ppm( 1 ), 1000 );\n}\n\nBOOST_AUTO_TEST_CASE( ppm_rounded_down )\n{\n    check_close( bll::delta_time::usec( 1000 * 1000 - 2 ).ppm( 44 ), 43 );\n    check_close( bll::delta_time::usec( 44 ).ppm( 1000 * 1000 - 2 ), 43 );\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "tests/link_layer/ll_advertising_tests.cpp",
    "content": "#include \"buffer_io.hpp\"\n\n#define BOOST_TEST_MODULE\n#include <boost/test/included/unit_test.hpp>\n#include <boost/mpl/list.hpp>\n\n#include <bluetoe/link_layer.hpp>\n#include <bluetoe/meta_tools.hpp>\n#include <bluetoe/custom_advertising.hpp>\n#include <bluetoe/server.hpp>\n#include \"test_radio.hpp\"\n#include \"connected.hpp\"\n#include \"test_servers.hpp\"\n\n#include <map>\n\nnamespace {\n\n    template < typename ... Options >\n    struct advertising_base : bluetoe::link_layer::link_layer< test::small_temperature_service, test::radio, Options... >\n    {\n        advertising_base()\n        {\n            this->run();\n        }\n    };\n\n    struct advertising : advertising_base< test::buffer_sizes > {};\n\n    template < typename ... Options >\n    struct advertising_and_connect_base : bluetoe::link_layer::link_layer< test::small_temperature_service, test::radio, Options... >\n    {\n        typedef bluetoe::link_layer::link_layer< test::small_temperature_service, test::radio, Options... > base;\n\n        void run()\n        {\n            base::run();\n        }\n\n        /*\n         * this function runs the simulation and checks that no response was generated\n         */\n        void run_expect_no_response( const char* message )\n        {\n            run();\n\n            this->check_scheduling(\n                []( const test::advertising_data& pdu ) -> bool\n                {\n                    return ( pdu.transmitted_data[ 0 ] & 0xf ) == 0;\n                },\n                message\n            );\n        }\n\n\n    };\n\n    struct advertising_and_connect : advertising_and_connect_base< test::buffer_sizes > {};\n\n    static const auto filter_channel_37 = []( const test::advertising_data& a )\n    {\n        return a.channel == 37;\n    };\n\n}\n\nBOOST_FIXTURE_TEST_CASE( advertising_scheduled, advertising )\n{\n    BOOST_CHECK_GT( advertisings().size(), 0u );\n}\n\nBOOST_FIXTURE_TEST_CASE( advertising_uses_all_three_adv_channels, advertising )\n{\n    std::map< unsigned, unsigned > channel;\n\n    all_data( [&]( const test::advertising_data& d ) { ++channel[ d.channel ]; } );\n\n    BOOST_CHECK_EQUAL( channel.size(), 3u );\n    BOOST_CHECK_GT( channel[ 37 ], 0u );\n    BOOST_CHECK_GT( channel[ 38 ], 0u );\n    BOOST_CHECK_GT( channel[ 39 ], 0u );\n}\n\nBOOST_FIXTURE_TEST_CASE( channels_are_iterated, advertising )\n{\n    check_scheduling(\n        [&]( const test::advertising_data& a, const test::advertising_data& b )\n        {\n            return a.channel != b.channel;\n        },\n        \"channels_are_iterated\"\n    );\n}\n\n/**\n * @test by default, the link layer will advertise Connectable Undirected Events\n */\nBOOST_FIXTURE_TEST_CASE( connectable_undirected_is_the_default, advertising )\n{\n    check_scheduling(\n        [&]( const test::advertising_data& scheduled ) -> bool\n        {\n            return !scheduled.transmitted_data.empty()\n                && ( scheduled.transmitted_data[ 0 ] & 0xf ) == 0;\n        },\n        \"connectable_undirected_is_the_default\"\n    );\n}\n\n/**\n * @test according to the specs, the distance between two advertising PDUs shall be shorter than or equal to 10ms\n *       We identify the start of an advertising event by the first channel 37\n */\nBOOST_FIXTURE_TEST_CASE( less_than_10ms_between_two_PDUs, advertising )\n{\n    check_scheduling(\n        [&]( const test::advertising_data& a, const test::advertising_data& b )\n        {\n            return ( a.channel != 37 && a.channel != 38 )\n                || ( b.on_air_time - a.on_air_time ) <= bluetoe::link_layer::delta_time::msec( 10 );\n        },\n        \"less_than_10ms_between_two_PDUs\"\n    );\n}\n\nBOOST_FIXTURE_TEST_CASE( correct_access_address_is_used, advertising )\n{\n    check_scheduling(\n        []( const test::advertising_data& data )\n        {\n            return data.access_address == 0x8E89BED6;\n        },\n        \"correct_access_address_is_used\"\n    );\n}\n\nBOOST_FIXTURE_TEST_CASE( correct_crc_init_is_used, advertising )\n{\n    check_scheduling(\n        []( const test::advertising_data& data )\n        {\n            return data.crc_init == 0x555555;\n        },\n        \"correct_crc_init_is_used\"\n    );\n}\n\n/**\n * @test the advertising interval is 50ms plus a pseudo random interval of 0ms to 10ms\n */\nusing interval_50_ms = advertising_base< bluetoe::link_layer::advertising_interval< 50 >, test::buffer_sizes >;\nBOOST_FIXTURE_TEST_CASE( configured_advertising_interval_is_kept, interval_50_ms )\n{\n    check_scheduling(\n        filter_channel_37,\n        [&]( const test::advertising_data& a, const test::advertising_data& b )\n        {\n            const auto diff = b.on_air_time - a.on_air_time;\n\n            return diff >= bluetoe::link_layer::delta_time::msec( 50 )\n                && diff <= bluetoe::link_layer::delta_time::msec( 60 );\n        },\n        \"configured_advertising_interval_is_kept\"\n    );\n}\n\n/**\n * @test by default, the interval is 100ms\n */\nBOOST_FIXTURE_TEST_CASE( default_advertising_interval_is_kept, advertising )\n{\n    check_scheduling(\n        filter_channel_37,\n        [&]( const test::advertising_data& a, const test::advertising_data& b )\n        {\n            const auto diff = b.on_air_time - a.on_air_time;\n\n            return diff >= bluetoe::link_layer::delta_time::msec( 100 )\n                && diff <= bluetoe::link_layer::delta_time::msec( 110 );\n        },\n        \"configured_advertising_interval_is_kept\"\n    );\n}\n\n/**\n * @test perturbation looks quit random\n * - no two adjanced equal values\n * - all values are equally distributed.\n */\nBOOST_FIXTURE_TEST_CASE( perturbation_looks_quit_random, advertising )\n{\n    std::map< bluetoe::link_layer::delta_time, unsigned >   perturbations;\n    bluetoe::link_layer::delta_time                         last_perturbation = bluetoe::link_layer::delta_time::now();\n\n    all_data(\n        filter_channel_37,\n        [&]( const test::advertising_data& a, const test::advertising_data& b )\n        {\n            const auto current_perturbation = b.on_air_time - a.on_air_time - bluetoe::link_layer::delta_time::msec( 100 );\n\n            if ( !perturbations.empty() )\n            {\n                BOOST_CHECK_NE( last_perturbation, current_perturbation );\n            }\n\n            ++perturbations[ current_perturbation ];\n            last_perturbation = current_perturbation;\n        }\n    );\n\n    double average = 0.0;\n    unsigned count = 0;\n\n    for ( auto p : perturbations )\n    {\n        average += p.first.usec() * p.second;\n        count   += p.second;\n    }\n\n    BOOST_CHECK_CLOSE_FRACTION( ( average / count ), 5.0 * 1000, 0.2 );\n}\n\nBOOST_FIXTURE_TEST_CASE( sending_advertising_pdus, advertising )\n{\n    check_scheduling(\n        []( const test::advertising_data& data )\n        {\n            const auto& pdu = data.transmitted_data;\n\n            return pdu.size() >= 2 && ( pdu[ 0 ] & 0x0f ) == 0;\n        },\n        \"sending_advertising_pdus\"\n    );\n}\n\nBOOST_FIXTURE_TEST_CASE( advertising_pdus_contain_the_address, advertising )\n{\n    static const bluetoe::link_layer::address expected_address = bluetoe::link_layer::address::generate_static_random_address( 0x47110815 );\n\n    check_scheduling(\n        [&]( const test::advertising_data& data )\n        {\n            const auto& pdu = data.transmitted_data;\n            return pdu.size() >= 8 && bluetoe::link_layer::address( &pdu[ 2 ] ) == expected_address;\n        },\n        \"advertising_pdus_contain_the_address\"\n    );\n}\n\nBOOST_FIXTURE_TEST_CASE( txadd_and_rxadd_bits_are_set_corretly_for_random_address, advertising )\n{\n    check_scheduling(\n        [&]( const test::advertising_data& data )\n        {\n            const auto& pdu = data.transmitted_data;\n            return pdu.size() >= 1 && ( pdu[ 0 ] & ( 3 << 6 ) ) == ( 1 << 6 );\n        },\n        \"txadd_and_rxadd_bits_are_set_corretly_for_random_address\"\n    );\n}\n\nBOOST_FIXTURE_TEST_CASE( length_field_is_set_corretly, advertising )\n{\n    check_scheduling(\n        [&]( const test::advertising_data& data )\n        {\n            const auto& pdu = data.transmitted_data;\n            return pdu.size() >= 2 && ( pdu[ 1 ] & 0x3f ) == pdu.size() - 2;\n        },\n        \"length_field_is_set_corretly\"\n    );\n}\n\nBOOST_FIXTURE_TEST_CASE( pdus_contain_the_gap_data, advertising )\n{\n    std::uint8_t        gap[ 31 ];\n    const std::size_t   gap_size = advertising_data( &gap[ 0 ], sizeof( gap ) );\n\n    check_scheduling(\n        [&]( const test::advertising_data& data )\n        {\n            const auto& pdu = data.transmitted_data;\n            return pdu.size() == 8 + gap_size && std::equal( &pdu[ 8 ], &pdu[ 8 + gap_size ], &gap[ 0 ] );\n        },\n        \"pdus_contain_the_gap_data\"\n    );\n}\n\nBOOST_FIXTURE_TEST_CASE( no_repond_to_an_invalid_pdu, advertising_and_connect )\n{\n    respond_to(\n        37, // channel\n        {\n            0x03, 0x0C // just a header\n        }\n    );\n\n    run_expect_no_response( \"no_repond_to_an_invalid_pdu\" );\n}\n\n/**\n * @test no respond if the device is not addressed\n */\nBOOST_FIXTURE_TEST_CASE( no_repond_to_a_scan_request_with_different_address, advertising_and_connect )\n{\n    respond_to(\n        37, // channel\n        {\n            0x03, 0x0C, // header\n            0x01, 0x02, 0x03, 0x04, 0x05, 0x06, // scanner address\n            0x47, 0x11, 0x08, 0x15, 0x0f, 0xc1  // not advertiser address\n        }\n    );\n\n    run_expect_no_response( \"no_repond_to_a_scan_request_with_different_address\" );\n}\n\nBOOST_FIXTURE_TEST_CASE( still_advertising_after_an_invalid_pdu, advertising_and_connect )\n{\n    respond_to(\n        37, // channel\n        {\n            0x03, 0x06, // header\n            0x01, 0x02, 0x03, 0x04, 0x05, 0x06  // scanner address\n            // missing advertiser address\n        }\n    );\n\n    run();\n\n    const unsigned number_of_advertising_packages =\n        this->sum_data(\n            std::function< unsigned ( const test::advertising_data&, unsigned ) >(\n                []( const test::advertising_data& pdu, unsigned start_value )\n                {\n                    return ( pdu.transmitted_data[ 0 ] & 0xf ) == 0\n                        ? start_value + 1\n                        : start_value;\n                }\n            ),\n            0u\n        );\n\n    BOOST_CHECK_GT( number_of_advertising_packages, 5u );\n}\n\nBOOST_FIXTURE_TEST_CASE( after_beeing_connected_the_ll_starts_to_advertise_again, connected_and_timeout )\n{\n    BOOST_REQUIRE( !advertisings().empty() );\n    auto const adv = advertisings().back();\n\n    BOOST_REQUIRE( !connection_events().empty() );\n    auto const con = connection_events().back();\n\n    BOOST_CHECK_GT( adv.schedule_time, con.schedule_time );\n}\n\nBOOST_FIXTURE_TEST_CASE( after_advertising_again_the_right_crc_have_to_be_used, connected_and_timeout )\n{\n    auto const adv = advertisings().back();\n\n    BOOST_CHECK_EQUAL( adv.crc_init, 0x555555u );\n}\n\nBOOST_FIXTURE_TEST_CASE( after_advertising_again_the_right_access_address_have_to_be_used, connected_and_timeout )\n{\n    auto const adv = advertisings().back();\n\n    BOOST_CHECK_EQUAL( adv.access_address, 0x8E89BED6u );\n}\n\nusing advertising_connectable_undirected_advertising  =\n    advertising_base<\n        bluetoe::link_layer::connectable_undirected_advertising,\n        test::buffer_sizes\n    >;\n\nBOOST_FIXTURE_TEST_CASE( starting_advertising_connectable_undirected_advertising, advertising_connectable_undirected_advertising )\n{\n    const auto number_of_advertising_pdus =\n        count_data( []( const test::advertising_data& scheduled ) -> bool\n        {\n            return !scheduled.transmitted_data.empty()\n                && ( scheduled.transmitted_data[ 0 ] & 0xf ) == 0;\n        } );\n\n    BOOST_CHECK_GT( number_of_advertising_pdus, 0u );\n}\n\nBOOST_AUTO_TEST_SUITE( connectable_directed_advertising )\n\nusing advertising_connectable_directed_advertising  =\n    advertising_base<\n        bluetoe::link_layer::connectable_directed_advertising,\n        test::buffer_sizes\n    >;\n\n// an address is needed to start the advertising\nBOOST_FIXTURE_TEST_CASE( directed_advertising_doesnt_starts_by_default, advertising_connectable_directed_advertising )\n{\n    BOOST_CHECK_EQUAL( 0u, count_data( []( const test::advertising_data& ) -> bool {\n        return true;\n    } ) );\n}\n\n//\nBOOST_FIXTURE_TEST_CASE( starting_connectable_directed_advertising, advertising_connectable_directed_advertising )\n{\n    directed_advertising_address( bluetoe::link_layer::public_device_address( { 0x00, 0x00, 0x00, 0x01, 0x0f, 0xc0 } ) );\n\n    run();\n    BOOST_CHECK_GT( advertisings().size(), 0u );\n}\n\nstruct started_directed_advertising : bluetoe::link_layer::link_layer< test::small_temperature_service, test::radio, bluetoe::link_layer::connectable_directed_advertising >\n{\n    started_directed_advertising()\n    {\n        directed_advertising_address( bluetoe::link_layer::public_device_address( { 0x00, 0x00, 0x00, 0x01, 0x0f, 0xc0 } ) );\n        this->run();\n    }\n};\n\nBOOST_FIXTURE_TEST_CASE( stop_connectable_directed_advertising, started_directed_advertising )\n{\n    directed_advertising_address( bluetoe::link_layer::device_address() );\n\n    run();\n    clear_events();\n\n    BOOST_CHECK_EQUAL( 0u, count_data( []( const test::advertising_data& ) -> bool {\n        return true;\n    } ) );\n}\n\nBOOST_FIXTURE_TEST_CASE( correct_size_and_type, started_directed_advertising )\n{\n    check_scheduling(\n        [&]( const test::advertising_data& data )\n        {\n            const auto& pdu = data.transmitted_data;\n\n            return pdu.size() == 2 * 6 + 2\n                && ( pdu[ 0 ] & 0xf ) == 1\n                && ( pdu[ 1 ] & 0x3f ) == 2 * 6;\n        },\n        \"correct_size_and_type\"\n    );\n}\n\nBOOST_FIXTURE_TEST_CASE( contains_local_address, started_directed_advertising )\n{\n    const auto address = local_address();\n\n    check_scheduling(\n        [&]( const test::advertising_data& data )\n        {\n            const auto& pdu = data.transmitted_data;\n\n            return pdu.size() >= 8\n                && std::equal( &pdu[ 2 ], &pdu[ 8 ], address.begin() )\n                && ( pdu[ 0 ] & 0x40 ) != 0;\n        },\n        \"contains_local_address\"\n    );\n}\n\nBOOST_FIXTURE_TEST_CASE( contains_remote_address, started_directed_advertising )\n{\n    const auto address = bluetoe::link_layer::public_device_address( { 0x00, 0x00, 0x00, 0x01, 0x0f, 0xc0 } );\n\n    check_scheduling(\n        [&]( const test::advertising_data& data )\n        {\n            const auto& pdu = data.transmitted_data;\n\n            return pdu.size() >= 14\n                && std::equal( &pdu[ 8 ], &pdu[ 14 ], address.begin() )\n                && ( pdu[ 0 ] & 0x80 ) == 0;\n        },\n        \"contains_remote_address\"\n    );\n}\n\nBOOST_FIXTURE_TEST_CASE( is_connectable_from_directed_address, started_directed_advertising )\n{\n    BOOST_REQUIRE( connection_events().empty() );\n\n    respond_to(\n        37,\n        {\n            0x85, 0x22,                         // header\n            0x00, 0x00, 0x00, 0x01, 0x0f, 0xc0, // InitA: c0:0f:01:00:00:00 (public)\n            0x47, 0x11, 0x08, 0x15, 0x0f, 0xc0, // AdvA:  c0:0f:15:08:11:47 (random)\n            0x5a, 0xb3, 0x9a, 0xaf,             // Access Address\n            0x08, 0x81, 0xf6,                   // CRC Init\n            0x03,                               // transmit window size\n            0x0b, 0x00,                         // window offset\n            0x18, 0x00,                         // interval\n            0x00, 0x00,                         // peripheral latency\n            0x48, 0x00,                         // connection timeout\n            0xff, 0xff, 0xff, 0xff, 0x1f,       // used channel map\n            0xaa                                // hop increment and sleep clock accuracy\n        }\n    );\n\n    end_of_simulation( bluetoe::link_layer::delta_time::seconds( 20 ) );\n    run();\n\n    BOOST_CHECK( !connection_events().empty() );\n}\n\nBOOST_FIXTURE_TEST_CASE( is_not_connectable_from_other_addresses, started_directed_advertising )\n{\n    BOOST_REQUIRE( connection_events().empty() );\n\n    respond_to(\n        37,\n        {\n            0xc5, 0x22,                         // header\n            0x3c, 0x1c, 0x62, 0x92, 0xf0, 0x48, // InitA: 48:f0:92:62:1c:3c (random)\n            0x47, 0x11, 0x08, 0x15, 0x0f, 0xc0, // AdvA:  c0:0f:15:08:11:47 (random)\n            0x5a, 0xb3, 0x9a, 0xaf,             // Access Address\n            0x08, 0x81, 0xf6,                   // CRC Init\n            0x03,                               // transmit window size\n            0x0b, 0x00,                         // window offset\n            0x18, 0x00,                         // interval\n            0x00, 0x00,                         // peripheral latency\n            0x48, 0x00,                         // connection timeout\n            0xff, 0xff, 0xff, 0xff, 0x1f,       // used channel map\n            0xaa                                // hop increment and sleep clock accuracy\n        }\n    );\n\n    end_of_simulation( bluetoe::link_layer::delta_time::seconds( 20 ) );\n    run();\n\n    BOOST_CHECK( connection_events().empty() );\n}\n\nBOOST_FIXTURE_TEST_CASE( no_response_to_scan_request, started_directed_advertising )\n{\n    respond_to(\n        37, // channel\n        {\n            0xC3, 0x0C, // header\n            0x01, 0x02, 0x03, 0x04, 0x05, 0x06, // scanner address\n            0x47, 0x11, 0x08, 0x15, 0x0f, 0xc0  // advertiser address\n        }\n    );\n\n    end_of_simulation( bluetoe::link_layer::delta_time::seconds( 20 ) );\n    run();\n\n    check_scheduling(\n        [&]( const test::advertising_data& data )\n        {\n            const auto& pdu = data.transmitted_data;\n\n            return pdu.size() >= 1\n                && ( pdu[ 0 ] & 0xf ) == 1;\n        },\n        \"no_response_to_scan_request\"\n    );\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE( non_connectable_undirected_advertising )\n\nstruct non_connectable_undirected_advertising :\n    bluetoe::link_layer::link_layer< test::small_temperature_service, test::radio, bluetoe::link_layer::non_connectable_undirected_advertising, test::buffer_sizes >\n{\n};\n\nBOOST_FIXTURE_TEST_CASE( starting_advertising, non_connectable_undirected_advertising )\n{\n    this->run();\n\n    BOOST_CHECK_GT( advertisings().size(), 0u );\n}\n\nBOOST_FIXTURE_TEST_CASE( correct_type_and_size, non_connectable_undirected_advertising )\n{\n    this->run();\n\n    check_scheduling(\n        [&]( const test::advertising_data& data )\n        {\n            const auto& pdu = data.transmitted_data;\n\n            return pdu.size() >= 2\n                && ( pdu[ 0 ] & 0xf ) == 2\n                && ( pdu[ 1 ] & 0x3f ) == pdu.size() - 2;\n        },\n        \"correct_type_and_size\"\n    );\n}\n\nBOOST_FIXTURE_TEST_CASE( contains_local_address, non_connectable_undirected_advertising )\n{\n    this->run();\n    const auto address = local_address();\n\n    check_scheduling(\n        [&]( const test::advertising_data& data )\n        {\n            const auto& pdu = data.transmitted_data;\n\n            return pdu.size() >= 8\n                && std::equal( &pdu[ 2 ], &pdu[ 8 ], address.begin() )\n                && ( pdu[ 0 ] & 0x40 ) != 0;\n        },\n        \"contains_local_address\"\n    );\n}\n\nBOOST_FIXTURE_TEST_CASE( no_response_to_connection_request_request, non_connectable_undirected_advertising )\n{\n    respond_to(\n        37,\n        {\n            0xc5, 0x22,                         // header\n            0x00, 0x00, 0x00, 0x01, 0x0f, 0xc0, // InitA: c0:0f:01:00:00:00 (random)\n            0x47, 0x11, 0x08, 0x15, 0x0f, 0xc0, // AdvA:  c0:0f:15:08:11:47 (random)\n            0x5a, 0xb3, 0x9a, 0xaf,             // Access Address\n            0x08, 0x81, 0xf6,                   // CRC Init\n            0x03,                               // transmit window size\n            0x0b, 0x00,                         // window offset\n            0x18, 0x00,                         // interval\n            0x00, 0x00,                         // peripheral latency\n            0x48, 0x00,                         // connection timeout\n            0xff, 0xff, 0xff, 0xff, 0x1f,       // used channel map\n            0xaa                                // hop increment and sleep clock accuracy\n        }\n    );\n\n    run();\n\n    BOOST_CHECK( connection_events().empty() );\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE( scannable_undirected_advertising )\n\nstruct scannable_undirected_advertising :\n    bluetoe::link_layer::link_layer< test::small_temperature_service, test::radio, bluetoe::link_layer::scannable_undirected_advertising, test::buffer_sizes >\n{\n};\n\nBOOST_FIXTURE_TEST_CASE( starting_advertising, scannable_undirected_advertising )\n{\n    this->run();\n\n    BOOST_CHECK_GT( advertisings().size(), 0u );\n}\n\nBOOST_FIXTURE_TEST_CASE( correct_type_and_size, scannable_undirected_advertising )\n{\n    this->run();\n\n    check_scheduling(\n        [&]( const test::advertising_data& data )\n        {\n            const auto& pdu = data.transmitted_data;\n\n            return pdu.size() >= 2\n                && ( pdu[ 0 ] & 0xf ) == 6\n                && ( pdu[ 1 ] & 0x3f ) == pdu.size() - 2;\n        },\n        \"correct_type_and_size\"\n    );\n}\n\nBOOST_FIXTURE_TEST_CASE( contains_local_address, scannable_undirected_advertising )\n{\n    this->run();\n    const auto address = local_address();\n\n    check_scheduling(\n        [&]( const test::advertising_data& data )\n        {\n            const auto& pdu = data.transmitted_data;\n\n            return pdu.size() >= 8\n                && std::equal( &pdu[ 2 ], &pdu[ 8 ], address.begin() )\n                && ( pdu[ 0 ] & 0x40 ) != 0;\n        },\n        \"contains_local_address\"\n    );\n}\n\nBOOST_FIXTURE_TEST_CASE( no_response_to_connection_request_request, scannable_undirected_advertising )\n{\n    respond_to(\n        37,\n        {\n            0xc5, 0x22,                         // header\n            0x00, 0x00, 0x00, 0x01, 0x0f, 0xc0, // InitA: c0:0f:01:00:00:00 (random)\n            0x47, 0x11, 0x08, 0x15, 0x0f, 0xc0, // AdvA:  c0:0f:15:08:11:47 (random)\n            0x5a, 0xb3, 0x9a, 0xaf,             // Access Address\n            0x08, 0x81, 0xf6,                   // CRC Init\n            0x03,                               // transmit window size\n            0x0b, 0x00,                         // window offset\n            0x18, 0x00,                         // interval\n            0x00, 0x00,                         // peripheral latency\n            0x48, 0x00,                         // connection timeout\n            0xff, 0xff, 0xff, 0xff, 0x1f,       // used channel map\n            0xaa                                // hop increment and sleep clock accuracy\n        }\n    );\n\n    run();\n\n    BOOST_CHECK( connection_events().empty() );\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE( multiple_advertising_types )\n\nstruct scannable_and_connectable_advertising :\n    bluetoe::link_layer::link_layer<\n        test::small_temperature_service, test::radio,\n        bluetoe::link_layer::connectable_undirected_advertising,\n        bluetoe::link_layer::scannable_undirected_advertising,\n        test::buffer_sizes\n    >\n{\n};\n\nBOOST_FIXTURE_TEST_CASE( advertising_starts_with_the_first_named_type, scannable_and_connectable_advertising )\n{\n    run();\n\n    BOOST_REQUIRE( !advertisings().empty() );\n\n    check_scheduling(\n        [&]( const test::advertising_data& data )\n        {\n            const auto& pdu = data.transmitted_data;\n\n            return pdu.size() >= 1\n                && ( pdu[ 0 ] & 0xf ) == 0;\n        },\n        \"advertising_starts_with_the_first_names_type\"\n    );\n}\n\nBOOST_FIXTURE_TEST_CASE( advertising_is_repeated_after_timeout, scannable_and_connectable_advertising )\n{\n    run();\n\n    const auto number_of_advertising_pdus =\n        count_data( []( const test::advertising_data& scheduled ) -> bool\n        {\n            return !scheduled.transmitted_data.empty()\n                && ( scheduled.transmitted_data[ 0 ] & 0xf ) == 0;\n        } );\n\n    BOOST_CHECK_GT( number_of_advertising_pdus, 1u );\n}\n\nBOOST_FIXTURE_TEST_CASE( can_switch_type_before_starting, scannable_and_connectable_advertising )\n{\n    this->change_advertising< bluetoe::link_layer::scannable_undirected_advertising >();\n\n    run();\n\n    check_scheduling(\n        [&]( const test::advertising_data& data )\n        {\n            const auto& pdu = data.transmitted_data;\n\n            return pdu.size() >= 1\n                && ( pdu[ 0 ] & 0xf ) == 6;\n        },\n        \"advertising_starts_with_the_first_names_type\"\n    );\n}\n\nBOOST_FIXTURE_TEST_CASE( can_switch_type_after_starting, scannable_and_connectable_advertising )\n{\n    run();\n\n    this->change_advertising< bluetoe::link_layer::scannable_undirected_advertising >();\n\n    run();\n\n    // Both advertising types must be present now\n    BOOST_TEST(count_data(\n        [&]( const test::advertising_data& data )\n        {\n            const auto& pdu = data.transmitted_data;\n\n            return pdu.size() >= 1\n                &&  ( pdu[ 0 ] & 0xf ) == 0;\n        }) >= 0u );\n\n    BOOST_TEST(count_data(\n        [&]( const test::advertising_data& data )\n        {\n            const auto& pdu = data.transmitted_data;\n\n            return pdu.size() >= 1\n                &&  ( pdu[ 0 ] & 0xf ) == 6;\n        }) >= 0u );\n}\n\nBOOST_FIXTURE_TEST_CASE( switching_type_is_not_defered_until_the_next_adv_start, scannable_and_connectable_advertising )\n{\n    run();\n\n    this->change_advertising< bluetoe::link_layer::scannable_undirected_advertising >();\n\n    respond_to(\n        37,\n        {\n            0xc5, 0x22,                         // header\n            0x00, 0x00, 0x00, 0x01, 0x0f, 0xc0, // InitA: c0:0f:01:00:00:00 (random)\n            0x47, 0x11, 0x08, 0x15, 0x0f, 0xc0, // AdvA:  c0:0f:15:08:11:47 (random)\n            0x5a, 0xb3, 0x9a, 0xaf,             // Access Address\n            0x08, 0x81, 0xf6,                   // CRC Init\n            0x03,                               // transmit window size\n            0x0b, 0x00,                         // window offset\n            0x18, 0x00,                         // interval\n            0x00, 0x00,                         // peripheral latency\n            0x48, 0x00,                         // connection timeout\n            0xff, 0xff, 0xff, 0xff, 0x1f,       // used channel map\n            0xaa                                // hop increment and sleep clock accuracy\n        }\n    );\n\n    end_of_simulation( bluetoe::link_layer::delta_time::seconds( 20 ) );\n    run();\n\n    BOOST_REQUIRE( connection_events().empty() );\n\n    BOOST_CHECK_GT( count_data(\n        [&]( const test::advertising_data& data )\n        {\n            const auto& pdu = data.transmitted_data;\n\n            return pdu.size() >= 1\n                && ( pdu[ 0 ] & 0xf ) == 6;\n        }), 0u );\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE( variable_advertising_interval )\n\nstruct variable_interval_multiple_types :\n    bluetoe::link_layer::link_layer<\n        test::small_temperature_service, test::radio,\n        bluetoe::link_layer::connectable_undirected_advertising,\n        bluetoe::link_layer::scannable_undirected_advertising,\n        bluetoe::link_layer::variable_advertising_interval,\n        test::buffer_sizes\n    >\n{\n};\n\nBOOST_FIXTURE_TEST_CASE( the_default_is_100ms, variable_interval_multiple_types )\n{\n    this->run();\n\n    check_scheduling(\n        filter_channel_37,\n        [&]( const test::advertising_data& a, const test::advertising_data& b )\n        {\n            const auto diff = b.on_air_time - a.on_air_time;\n\n            return diff >= bluetoe::link_layer::delta_time::msec( 100 )\n                && diff <= bluetoe::link_layer::delta_time::msec( 110 );\n        },\n        \"the_default_is_100ms\"\n    );\n}\n\nBOOST_FIXTURE_TEST_CASE( changeable_to_30, variable_interval_multiple_types )\n{\n    advertising_interval_ms( 30 );\n    run();\n\n    check_scheduling(\n        filter_channel_37,\n        [&]( const test::advertising_data& a, const test::advertising_data& b )\n        {\n            const auto diff = b.on_air_time - a.on_air_time;\n\n            return diff >= bluetoe::link_layer::delta_time::msec( 30 )\n                && diff <= bluetoe::link_layer::delta_time::msec( 40 );\n        },\n        \"changeable_to_300\"\n    );\n}\n\nstruct variable_interval_single_type :\n    bluetoe::link_layer::link_layer<\n        test::small_temperature_service, test::radio,\n        bluetoe::link_layer::variable_advertising_interval,\n        test::buffer_sizes\n    >\n{\n};\n\nBOOST_FIXTURE_TEST_CASE( works_for_single_types_too, variable_interval_single_type )\n{\n    advertising_interval_ms( 30 );\n    run();\n\n    check_scheduling(\n        filter_channel_37,\n        [&]( const test::advertising_data& a, const test::advertising_data& b )\n        {\n            const auto diff = b.on_air_time - a.on_air_time;\n\n            return diff >= bluetoe::link_layer::delta_time::msec( 30 )\n                && diff <= bluetoe::link_layer::delta_time::msec( 40 );\n        },\n        \"changeable_to_300\"\n    );\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE( no_auto_start_advertising )\n\nstruct no_auto_start_single_type :\n    bluetoe::link_layer::link_layer<\n        test::small_temperature_service, test::radio,\n        bluetoe::link_layer::no_auto_start_advertising,\n        test::buffer_sizes\n    >\n{\n};\n\nstruct no_auto_start_multiple_type :\n    bluetoe::link_layer::link_layer<\n        test::small_temperature_service, test::radio,\n        bluetoe::link_layer::no_auto_start_advertising,\n        bluetoe::link_layer::connectable_undirected_advertising,\n        bluetoe::link_layer::scannable_undirected_advertising,\n        test::buffer_sizes\n    >\n{\n};\n\ntypedef boost::mpl::list<\n    no_auto_start_single_type,\n    no_auto_start_multiple_type > all_fixtures;\n\nBOOST_AUTO_TEST_CASE_TEMPLATE( no_automatic_start_single, LinkLayer, all_fixtures )\n{\n    LinkLayer link_layer;\n    link_layer.run();\n    BOOST_CHECK_EQUAL( 0u, link_layer.advertisings().size() );\n}\n\nBOOST_AUTO_TEST_CASE_TEMPLATE( manuell_start_before, LinkLayer, all_fixtures )\n{\n    LinkLayer link_layer;\n    link_layer.start_advertising();\n    link_layer.run();\n\n    BOOST_CHECK_NE( 0u, link_layer.advertisings().size() );\n}\n\nBOOST_AUTO_TEST_CASE_TEMPLATE( manuell_start_single_after, LinkLayer, all_fixtures )\n{\n    LinkLayer link_layer;\n    link_layer.run();\n\n    link_layer.start_advertising();\n\n    link_layer.end_of_simulation( bluetoe::link_layer::delta_time::seconds( 20 ) );\n    link_layer.run();\n\n    BOOST_CHECK_NE( 0u, link_layer.advertisings().size() );\n}\n\nBOOST_AUTO_TEST_CASE_TEMPLATE( no_automatic_start_after_disconnect, LinkLayer, all_fixtures )\n{\n    LinkLayer link_layer;\n    link_layer.start_advertising();\n    link_layer.respond_to(\n        37,\n        {\n            0xc5, 0x22,                         // header\n            0x00, 0x00, 0x00, 0x01, 0x0f, 0xc0, // InitA: c0:0f:01:00:00:00 (random)\n            0x47, 0x11, 0x08, 0x15, 0x0f, 0xc0, // AdvA:  c0:0f:15:08:11:47 (random)\n            0x5a, 0xb3, 0x9a, 0xaf,             // Access Address\n            0x08, 0x81, 0xf6,                   // CRC Init\n            0x03,                               // transmit window size\n            0x0b, 0x00,                         // window offset\n            0x18, 0x00,                         // interval\n            0x00, 0x00,                         // peripheral latency\n            0x48, 0x00,                         // connection timeout\n            0xff, 0xff, 0xff, 0xff, 0x1f,       // used channel map\n            0xaa                                // hop increment and sleep clock accuracy\n        }\n    );\n\n    link_layer.run();\n\n    BOOST_REQUIRE( !link_layer.connection_events().empty() );\n    const auto connect_time = link_layer.connection_events().front().schedule_time;\n\n    link_layer.check_scheduling(\n        [&]( const test::advertising_data& adv )\n        {\n            return adv.schedule_time <= connect_time;\n        },\n        \"no_automatic_start_after_disconnect\"\n    );\n}\n\nBOOST_AUTO_TEST_CASE_TEMPLATE( stop_advertising_test, LinkLayer, all_fixtures )\n{\n    LinkLayer link_layer;\n    link_layer.start_advertising();\n    link_layer.run();\n\n    const auto adv_count = link_layer.advertisings().size();\n    link_layer.stop_advertising();\n\n    link_layer.end_of_simulation( bluetoe::link_layer::delta_time::seconds( 20 ) );\n    link_layer.run();\n\n    BOOST_CHECK_EQUAL( link_layer.advertisings().size(), adv_count );\n}\n\nBOOST_AUTO_TEST_CASE_TEMPLATE( stop_advertising_after_one_advertisements, LinkLayer, all_fixtures )\n{\n    LinkLayer link_layer;\n    link_layer.start_advertising( 1u );\n    link_layer.run();\n\n    BOOST_CHECK_EQUAL( 1u, link_layer.advertisings().size() );\n}\n\nBOOST_AUTO_TEST_CASE_TEMPLATE( stop_advertising_after_certain_advertisements, LinkLayer, all_fixtures )\n{\n    LinkLayer link_layer;\n    link_layer.start_advertising( 42u );\n    link_layer.run();\n\n    BOOST_CHECK_EQUAL( 42u, link_layer.advertisings().size() );\n}\n\nBOOST_AUTO_TEST_CASE_TEMPLATE( restart_after_count_down, LinkLayer, all_fixtures )\n{\n    LinkLayer link_layer;\n    link_layer.start_advertising( 42u );\n    link_layer.run();\n\n    BOOST_CHECK_EQUAL( 42u, link_layer.advertisings().size() );\n\n    link_layer.start_advertising();\n    link_layer.end_of_simulation( bluetoe::link_layer::delta_time::seconds( 20 ) );\n    link_layer.run();\n\n    BOOST_CHECK_GT( link_layer.advertisings().size(), 42u );\n}\n\nBOOST_AUTO_TEST_CASE_TEMPLATE( stop_count_down, LinkLayer, all_fixtures )\n{\n    LinkLayer link_layer;\n    link_layer.start_advertising( 300 );\n    link_layer.run();\n\n    // 290 is simply the number of advertising PDUs send within 10 second\n    BOOST_REQUIRE_EQUAL( 290u, link_layer.advertisings().size() );\n\n    link_layer.start_advertising();\n\n    link_layer.end_of_simulation( bluetoe::link_layer::delta_time::seconds( 20 ) );\n    link_layer.run();\n\n    BOOST_CHECK_GT( link_layer.advertisings().size(), 550u );\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE( advertising_custom_data )\n\n    static const std::uint8_t custom_advertising_data[] = {\n        0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07\n    };\n\n    static const std::uint8_t custom_response_data[] = {\n        0x11, 0x22, 0x33, 0x44, 0x55\n    };\n\n    using server = bluetoe::extend_server<\n        test::small_temperature_service,\n        bluetoe::custom_advertising_data< sizeof( custom_advertising_data ), custom_advertising_data >,\n        bluetoe::custom_scan_response_data< sizeof( custom_response_data ), custom_response_data >\n    >;\n\n    template < typename ... Options >\n    struct custom_advertising : bluetoe::link_layer::link_layer< server, test::radio, Options... >\n    {\n        custom_advertising()\n        {\n            this->run();\n        }\n    };\n\n    BOOST_FIXTURE_TEST_CASE( advertising_data, custom_advertising<> )\n    {\n        run();\n\n        const std::uint8_t expected[] = {\n            0x40, 0x0d,                         // Header\n            0x47, 0x11, 0x08, 0x15, 0x0f, 0xc0, // AdvA:  c0:0f:15:08:11:47 (random)\n            0x01, 0x02, 0x03, 0x04, 0x05, 0x06, // data\n            0x07\n        };\n\n        check_scheduling(\n            [&]( const test::advertising_data& data )\n            {\n                const auto& pdu = data.transmitted_data;\n\n                return pdu.size() == sizeof( expected )\n                    && std::equal( pdu.begin(), pdu.end(), std::begin( expected ) );\n            },\n            \"advertsing data\"\n        );\n    }\n\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE( channel_map )\n\n    using variable_channel_map = advertising_base<\n        bluetoe::link_layer::variable_advertising_channel_map,\n        bluetoe::link_layer::no_auto_start_advertising >;\n\n    BOOST_FIXTURE_TEST_CASE( advertising_uses_all_three_adv_channels, variable_channel_map )\n    {\n        std::map< unsigned, unsigned > channel;\n        start_advertising();\n\n        run();\n\n        all_data( [&]( const test::advertising_data& d ) { ++channel[ d.channel ]; } );\n\n        BOOST_CHECK_EQUAL( channel.size(), 3u );\n        BOOST_CHECK_GT( channel[ 37 ], 0u );\n        BOOST_CHECK_GT( channel[ 38 ], 0u );\n        BOOST_CHECK_GT( channel[ 39 ], 0u );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( advertising_uses_just_2_adv_channels, variable_channel_map )\n    {\n        std::map< unsigned, unsigned > channel;\n        remove_channel_from_advertsing_channel_map( 37 );\n        start_advertising();\n\n        run();\n\n        all_data( [&]( const test::advertising_data& d ) { ++channel[ d.channel ]; } );\n\n        BOOST_CHECK_EQUAL( channel.size(), 2u );\n        BOOST_CHECK_EQUAL( channel[ 37 ], 0u );\n        BOOST_CHECK_GT( channel[ 38 ], 0u );\n        BOOST_CHECK_GT( channel[ 39 ], 0u );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( advertising_uses_just_1_adv_channels, variable_channel_map )\n    {\n        std::map< unsigned, unsigned > channel;\n        remove_channel_from_advertsing_channel_map( 37 );\n        remove_channel_from_advertsing_channel_map( 39 );\n        start_advertising();\n\n        run();\n\n        all_data( [&]( const test::advertising_data& d ) { ++channel[ d.channel ]; } );\n\n        BOOST_CHECK_EQUAL( channel.size(), 1u );\n        BOOST_CHECK_EQUAL( channel[ 37 ], 0u );\n        BOOST_CHECK_GT( channel[ 38 ], 0u );\n        BOOST_CHECK_EQUAL( channel[ 39 ], 0u );\n    }\n\n\n    BOOST_FIXTURE_TEST_CASE( advertising_uses_just_1_adv_channels_remove_all_and_add, variable_channel_map )\n    {\n        std::map< unsigned, unsigned > channel;\n        remove_channel_from_advertsing_channel_map( 37 );\n        remove_channel_from_advertsing_channel_map( 38 );\n        remove_channel_from_advertsing_channel_map( 39 );\n\n        add_channel_to_advertising_channel_map( 37 );\n\n        start_advertising();\n\n        run();\n\n        all_data( [&]( const test::advertising_data& d ) { ++channel[ d.channel ]; } );\n\n        BOOST_CHECK_EQUAL( channel.size(), 1u );\n        BOOST_CHECK_GT( channel[ 37 ], 0u );\n        BOOST_CHECK_EQUAL( channel[ 38 ], 0u );\n        BOOST_CHECK_EQUAL( channel[ 39 ], 0u );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( advertising_uses_all_three_adv_channels_observice_time, variable_channel_map )\n    {\n        std::vector< bluetoe::link_layer::delta_time > on_air_times;\n        start_advertising();\n\n        run();\n\n        all_data( [&]( const test::advertising_data& d ) { on_air_times.push_back( d.on_air_time ); } );\n\n        static const bluetoe::link_layer::delta_time expected[] = {\n            bluetoe::link_layer::delta_time::msec( 0 ),\n            bluetoe::link_layer::delta_time::msec( 0 ),\n            bluetoe::link_layer::delta_time::msec( 0 ),\n            bluetoe::link_layer::delta_time::msec( 107 ),\n            bluetoe::link_layer::delta_time::msec( 107 ),\n            bluetoe::link_layer::delta_time::msec( 107 ),\n            bluetoe::link_layer::delta_time::msec( 210 ),\n            bluetoe::link_layer::delta_time::msec( 210 ),\n            bluetoe::link_layer::delta_time::msec( 210 ),\n        };\n\n        static const auto expected_size = std::distance( std::begin(expected), std::end(expected) );\n\n        BOOST_REQUIRE_LE( expected_size, on_air_times.size() );\n        on_air_times.erase(\n            std::next( on_air_times.begin(), expected_size ), on_air_times.end() );\n\n        BOOST_CHECK_EQUAL_COLLECTIONS(\n            on_air_times.begin(), on_air_times.end(),\n            std::begin(expected), std::end(expected) );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( advertising_uses_single_adv_channels_observice_time, variable_channel_map )\n    {\n        std::vector< bluetoe::link_layer::delta_time > on_air_times;\n        remove_channel_from_advertsing_channel_map( 38 );\n        remove_channel_from_advertsing_channel_map( 39 );\n        start_advertising();\n\n        run();\n\n        all_data( [&]( const test::advertising_data& d ) { on_air_times.push_back( d.on_air_time ); } );\n\n        static const bluetoe::link_layer::delta_time expected[] = {\n            bluetoe::link_layer::delta_time::msec( 0 ),\n            bluetoe::link_layer::delta_time::msec( 107 ),\n            bluetoe::link_layer::delta_time::msec( 210 ),\n        };\n\n        static const auto expected_size = std::distance( std::begin(expected), std::end(expected) );\n\n        BOOST_REQUIRE_LE( expected_size, on_air_times.size() );\n        on_air_times.erase(\n            std::next( on_air_times.begin(), expected_size ), on_air_times.end() );\n\n        BOOST_CHECK_EQUAL_COLLECTIONS(\n            on_air_times.begin(), on_air_times.end(),\n            std::begin(expected), std::end(expected) );\n    }\n\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE( dynamically_changed_advertising_data )\n\n    using server = bluetoe::extend_server<\n        test::small_temperature_service,\n        bluetoe::runtime_custom_advertising_data,\n        bluetoe::runtime_custom_scan_response_data\n    >;\n\n    template < typename ... Options >\n    struct runtime_advertising : bluetoe::link_layer::link_layer< server, test::radio, Options... >\n    {\n        runtime_advertising()\n        {\n        }\n    };\n\n    using test_fixtures = std::tuple<\n        // Single advertisment type\n        runtime_advertising<>,\n        // multiple advertisment types\n        runtime_advertising<\n            bluetoe::link_layer::connectable_undirected_advertising,\n            bluetoe::link_layer::scannable_undirected_advertising >\n    >;\n\n    BOOST_AUTO_TEST_CASE_TEMPLATE( changed_advertising_data, fixture, test_fixtures )\n    {\n        fixture server;\n\n        static const std::uint8_t advertising_data1[ 5 ] = { 0x01, 0x02, 0x03, 0x04, 0x05 };\n        server.set_runtime_custom_advertising_data( std::begin( advertising_data1 ), 5 );\n        server.run();\n\n        auto last_advertising = server.advertisings().back().transmitted_data;\n        const std::initializer_list< std::uint8_t > expected1 = {\n            0x40, 0x0b,                             // header\n            0x47, 0x11, 0x08, 0x15, 0x0f, 0xc0,     // AdvA:  c0:0f:15:08:11:47 (random)\n            0x01, 0x02, 0x03, 0x04, 0x05\n        };\n\n        BOOST_CHECK_EQUAL_COLLECTIONS(\n            last_advertising.begin(), last_advertising.end(),\n            expected1.begin(), expected1.end() );\n\n        // now, change adverting data:\n        static const std::uint8_t advertising_data2[ 3 ] = { 0x0a, 0x0b, 0x0c };\n        server.set_runtime_custom_advertising_data( std::begin( advertising_data2 ), 3 );\n        server.run();\n\n        last_advertising = server.advertisings().back().transmitted_data;\n        const std::initializer_list< std::uint8_t > expected2 = {\n            0x40, 0x09,                             // header\n            0x47, 0x11, 0x08, 0x15, 0x0f, 0xc0,     // AdvA:  c0:0f:15:08:11:47 (random)\n            0x0a, 0x0b, 0x0c\n        };\n\n        BOOST_CHECK_EQUAL_COLLECTIONS(\n            last_advertising.begin(), last_advertising.end(),\n            expected2.begin(), expected2.end() );\n    }\n\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "tests/link_layer/ll_connecting_tests.cpp",
    "content": "#define BOOST_TEST_MODULE\n#include <boost/test/included/unit_test.hpp>\n#include <boost/test/unit_test.hpp>\n\n#include <iostream>\n#include \"buffer_io.hpp\"\n#include \"connected.hpp\"\n\n#include <type_traits>\n\nBOOST_FIXTURE_TEST_SUITE( starting_unconnected_tests, unconnected )\n\n/**\n * @test after a valid connection request, no further advertising packages are send.\n */\nBOOST_AUTO_TEST_CASE_TEMPLATE( connected_after_connection_request, Channel, advertising_channels )\n{\n    respond_to( Channel::value, valid_connection_request_pdu );\n\n    run();\n\n    BOOST_CHECK_GE( count_data(\n        [&]( const test::advertising_data& data ) -> bool\n        {\n            bool is_advertising = ( data.transmitted_data[ 0 ] & 0xf ) == 0;\n                 is_advertising = is_advertising && data.channel >= 37 && data.channel >= 40;\n\n            return !is_advertising;\n        } ), 1u );\n}\n\nBOOST_AUTO_TEST_CASE_TEMPLATE( no_connection_after_a_connection_request_with_wrong_length, Channel, advertising_channels )\n{\n    respond_to(\n        Channel::value,\n        {\n            0xc5 ^ 0xff, 0x22 ^ 0xff,           // header with wrong size\n            0x00, 0x00,                         // gap required by the test radio layout\n            0x3c, 0x1c, 0x62, 0x92, 0xf0, 0x48, // InitA: 48:f0:92:62:1c:3c (random)\n            0x47, 0x11, 0x08, 0x15, 0x0f, 0xc0, // AdvA:  c0:0f:15:08:11:47 (random)\n            0x5a, 0xb3, 0x9a, 0xaf,             // Access Address\n            0x08, 0x81, 0xf6,                   // CRC Init\n            0x03,                               // transmit window size\n            0x0b, 0x00,                         // window offset\n            0x18, 0x00,                         // interval\n            0x00, 0x00,                         // peripheral latency\n            0x48, 0x00,                         // connection timeout\n            0xff, 0xff, 0xff, 0xff, 0x1f        // used channel map\n        }\n    );\n\n    run();\n\n    check_not_connected( \"no_connection_after_a_connection_request_with_wrong_length\" );\n}\n\nBOOST_AUTO_TEST_CASE_TEMPLATE( no_connection_after_a_connection_request_with_wrong_length_header, Channel, advertising_channels )\n{\n    respond_to(\n        Channel::value,\n        {\n            0xc5 ^ 0xff, 0x21 ^ 0xff,           // header with wrong size\n            0x00, 0x00,                         // gap required by the test radio layout\n            0x3c, 0x1c, 0x62, 0x92, 0xf0, 0x48, // InitA: 48:f0:92:62:1c:3c (random)\n            0x47, 0x11, 0x08, 0x15, 0x0f, 0xc0, // AdvA:  c0:0f:15:08:11:47 (random)\n            0x5a, 0xb3, 0x9a, 0xaf,             // Access Address\n            0x08, 0x81, 0xf6,                   // CRC Init\n            0x03,                               // transmit window size\n            0x0b, 0x00,                         // window offset\n            0x18, 0x00,                         // interval\n            0x00, 0x00,                         // peripheral latency\n            0x48, 0x00,                         // connection timeout\n            0xff, 0xff, 0xff, 0xff, 0x1f,       // used channel map\n            0xaa                                // hop increment and sleep clock accuracy\n        }\n    );\n\n    run();\n\n    check_not_connected( \"no_connection_after_a_connection_request_with_wrong_length\" );\n}\n\nBOOST_AUTO_TEST_CASE_TEMPLATE( no_connection_after_a_connection_request_with_wrong_advertiser_address, Channel, advertising_channels )\n{\n    respond_to(\n        Channel::value,\n        {\n            0xc5, 0x22,                         // header\n            0x3c, 0x1c, 0x62, 0x92, 0xf0, 0x48, // InitA: 48:f0:92:62:1c:3c (random)\n            0x47, 0x11, 0x18, 0x15, 0x0f, 0xc0, // AdvA:  c0:0f:15:18:11:47 (random) (not the correct address)\n            0x5a, 0xb3, 0x9a, 0xaf,             // Access Address\n            0x08, 0x81, 0xf6,                   // CRC Init\n            0x03,                               // transmit window size\n            0x0b, 0x00,                         // window offset\n            0x18, 0x00,                         // interval\n            0x00, 0x00,                         // peripheral latency\n            0x48, 0x00,                         // connection timeout\n            0xff, 0xff, 0xff, 0xff, 0x1f,       // used channel map\n            0xaa                                // hop increment and sleep clock accuracy\n        }\n    );\n\n    run();\n\n    check_not_connected( \"no_connection_after_a_connection_request_with_wrong_advertiser_address\" );\n}\n\ntypedef boost::mpl::list<\n    std::integral_constant< unsigned, 0u >,\n    std::integral_constant< unsigned, 4u >,\n    std::integral_constant< unsigned, 17u > > invalid_hop_increments;\n\nBOOST_AUTO_TEST_CASE_TEMPLATE( no_connection_if_hop_is_invalid, HopIncrement, invalid_hop_increments )\n{\n    respond_to(\n        37,\n        {\n            0xc5, 0x22,                         // header\n            0x3c, 0x1c, 0x62, 0x92, 0xf0, 0x48, // InitA: 48:f0:92:62:1c:3c (random)\n            0x47, 0x11, 0x08, 0x15, 0x0f, 0xc0, // AdvA:  c0:0f:15:08:11:47 (random)\n            0x5a, 0xb3, 0x9a, 0xaf,             // Access Address\n            0x08, 0x81, 0xf6,                   // CRC Init\n            0x03,                               // transmit window size\n            0x0b, 0x00,                         // window offset\n            0x18, 0x00,                         // interval\n            0x00, 0x00,                         // peripheral latency\n            0x48, 0x00,                         // connection timeout\n            0xff, 0xff, 0xff, 0xff, 0x1f,       // used channel map\n            0xa0 | HopIncrement::value          // hop increment and sleep clock accuracy\n        }\n    );\n\n    run();\n\n    check_not_connected( \"no_connection_after_a_connection_request_with_wrong_advertiser_address\" );\n}\n\nBOOST_AUTO_TEST_CASE_TEMPLATE( no_connection_if_only_one_channel_is_used, Channel, advertising_channels )\n{\n    respond_to(\n        Channel::value,\n        {\n            0xc5, 0x22,                         // header\n            0x3c, 0x1c, 0x62, 0x92, 0xf0, 0x48, // InitA: 48:f0:92:62:1c:3c (random)\n            0x47, 0x11, 0x08, 0x15, 0x0f, 0xc0, // AdvA:  c0:0f:15:08:11:47 (random)\n            0x5a, 0xb3, 0x9a, 0xaf,             // Access Address\n            0x08, 0x81, 0xf6,                   // CRC Init\n            0x03,                               // transmit window size\n            0x0b, 0x00,                         // window offset\n            0x18, 0x00,                         // interval\n            0x00, 0x00,                         // peripheral latency\n            0x48, 0x00,                         // connection timeout\n            0x01, 0x00, 0x00, 0x00, 0x00,       // only channel 0\n            0xaa                                // hop increment and sleep clock accuracy\n        }\n    );\n\n    run();\n\n    check_not_connected( \"no_connection_if_only_one_channel_is_used\" );\n\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_FIXTURE_TEST_CASE( takes_the_give_access_address, unconnected )\n{\n    respond_to(\n        37,\n        {\n            0xc5, 0x22,                         // header\n            0x3c, 0x1c, 0x62, 0x92, 0xf0, 0x48, // InitA: 48:f0:92:62:1c:3c (random)\n            0x47, 0x11, 0x08, 0x15, 0x0f, 0xc0, // AdvA:  c0:0f:15:08:11:47 (random)\n            0x5a, 0xb3, 0x9a, 0xaf,             // Access Address\n            0x08, 0x81, 0xf6,                   // CRC Init\n            0x03,                               // transmit window size\n            0x0b, 0x00,                         // window offset\n            0x18, 0x00,                         // interval\n            0x00, 0x00,                         // peripheral latency\n            0x48, 0x00,                         // connection timeout\n            0xff, 0xff, 0xff, 0xff, 0x1f,       // used channel map\n            0xaa                                // hop increment and sleep clock accuracy\n        }\n    );\n\n    run();\n\n    BOOST_CHECK_EQUAL( connection_events().front().access_address, 0xaf9ab35a );\n}\n\nBOOST_FIXTURE_TEST_CASE( takes_the_give_initial_crc_value, unconnected )\n{\n    respond_to(\n        37,\n        {\n            0xc5, 0x22,                         // header\n            0x3c, 0x1c, 0x62, 0x92, 0xf0, 0x48, // InitA: 48:f0:92:62:1c:3c (random)\n            0x47, 0x11, 0x08, 0x15, 0x0f, 0xc0, // AdvA:  c0:0f:15:08:11:47 (random)\n            0x5a, 0xb3, 0x9a, 0xaf,             // Access Address\n            0x08, 0x81, 0xf6,                   // CRC Init\n            0x03,                               // transmit window size\n            0x0b, 0x00,                         // window offset\n            0x18, 0x00,                         // interval\n            0x00, 0x00,                         // peripheral latency\n            0x48, 0x00,                         // connection timeout\n            0xff, 0xff, 0xff, 0xff, 0x1f,       // used channel map\n            0xaa                                // hop increment and sleep clock accuracy\n        }\n    );\n\n    run();\n\n    BOOST_CHECK_EQUAL( connection_events().front().crc_init, 0xf68108u );\n}\n\nBOOST_FIXTURE_TEST_SUITE( starting_unconnected_tests, unconnected )\n\n/*\n * At the start of a connection event, unmappedChannel shall be calculated using the following basic algorithm:\n *    unmappedChannel = (lastUnmappedChannel + hopIncrement) mod 37; for the first connection event lastUnmappedChannel is zero.\n */\nBOOST_AUTO_TEST_CASE_TEMPLATE( start_receiving_on_the_correct_channel, Channel, advertising_channels )\n{\n    respond_to( Channel::value, valid_connection_request_pdu );\n\n    run();\n\n    BOOST_REQUIRE( !connection_events().empty() );\n    BOOST_CHECK_EQUAL( int( connection_events().front().channel ), ( 0 + 10 ) % 37 );\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n\n/*\n * Assumed that the first unmappedChannel is not within the channel map, the remapped channel should be used\n */\nBOOST_FIXTURE_TEST_CASE( start_receiving_on_a_remappped_channel, unconnected )\n{\n    respond_to(\n        38,\n        {\n            0xc5, 0x22,                         // header\n            0x3c, 0x1c, 0x62, 0x92, 0xf0, 0x48, // InitA: 48:f0:92:62:1c:3c (random)\n            0x47, 0x11, 0x08, 0x15, 0x0f, 0xc0, // AdvA:  c0:0f:15:08:11:47 (random)\n            0x5a, 0xb3, 0x9a, 0xaf,             // Access Address\n            0x08, 0x81, 0xf6,                   // CRC Init\n            0x03,                               // transmit window size\n            0x0b, 0x00,                         // window offset\n            0x18, 0x00,                         // interval\n            0x00, 0x00,                         // peripheral latency\n            0x48, 0x00,                         // connection timeout\n            0xff, 0xfb, 0xff, 0xff, 0x1f,       // used channel map\n            0xaa                                // hop increment and sleep clock accuracy\n        } );\n\n    run();\n\n    BOOST_REQUIRE( !connection_events().empty() );\n    BOOST_CHECK_EQUAL( connection_events().front().channel, unsigned{ ( ( 0 + 10 ) % 37 ) % 36 + 1 } );\n}\n\nBOOST_FIXTURE_TEST_CASE( no_connection_if_transmit_window_is_larger_than_10ms, unconnected )\n{\n    respond_with_connection_request(\n        0x09, // window_size\n        0x0b, // window_offset\n        0x18  // interval\n    );\n\n    run();\n\n    check_not_connected( \"no_connection_if_transmit_window_is_larger_than_10ms\" );\n}\n\nBOOST_FIXTURE_TEST_CASE( no_connection_if_transmit_window_is_larger_than_connection_interval, unconnected )\n{\n    respond_with_connection_request(\n        0x07, // window_size\n        0x0b, // window_offset\n        0x06  // interval\n    );\n\n    run();\n\n    check_not_connected( \"no_connection_if_transmit_window_is_larger_than_connection_interval\" );\n}\n\nBOOST_FIXTURE_TEST_CASE( no_connection_if_transmit_window_offset_is_larger_than_connection_interval, unconnected )\n{\n    respond_with_connection_request(\n        0x02, // window_size\n        0x0b, // window_offset\n        0x0a  // interval\n    );\n\n    run();\n\n    check_not_connected( \"no_connection_if_transmit_window_offset_is_larger_than_connection_interval\" );\n}\n\n/*\n * The default devie sleep clock accuracy is 500ppm, the centrals sca is 50ppm.\n * The last T0 was the reception of the connect request. The transmit window offset is\n * ( 11 + 1 ) * 1.25ms, the window size is 3 * 1.25 ms. So the window starts at:\n * 15ms - 15ms * 550ppm = 14992µs; the window ends at 18.75ms + 18.75ms * 550ppm = 18760µs\n */\nBOOST_FIXTURE_TEST_CASE( start_receiving_with_the_correct_window, connecting )\n{\n    BOOST_REQUIRE( !connection_events().empty() );\n\n    const auto& event = connection_events().front();\n\n    BOOST_CHECK_EQUAL( event.start_receive.usec(), 14992u );\n    BOOST_CHECK_EQUAL( event.end_receive.usec(), 18760u );\n    BOOST_CHECK_EQUAL( event.connection_interval.usec(), 30000u );\n}\n\n/*\n * Second example, with a different configured sleep clock accuracy of 100ppm.\n * The central is announcing a sleep clock accuracy of 250 ppm. In sum: 350ppm.\n *\n * Start at:\n *   2000ms - 350ppm = 1999300µs +-1µs\n * End at:\n *   ( 2000ms + 10ms ) + 350ppm = 2010703µs +-1µs\n */\nusing local_device_with_100ppm = unconnected_base< bluetoe::link_layer::sleep_clock_accuracy_ppm< 100 >, test::buffer_sizes >;\nBOOST_FIXTURE_TEST_CASE( start_receiving_with_the_correct_window_II, local_device_with_100ppm )\n{\n    respond_to(\n        37,\n        {\n            0xc5, 0x22,                         // header\n            0x3c, 0x1c, 0x62, 0x92, 0xf0, 0x48, // InitA: 48:f0:92:62:1c:3c (random)\n            0x47, 0x11, 0x08, 0x15, 0x0f, 0xc0, // AdvA:  c0:0f:15:08:11:47 (random)\n            0x5a, 0xb3, 0x9a, 0xaf,             // Access Address\n            0x08, 0x81, 0xf6,                   // CRC Init\n            0x08,                               // maximum transmit window size = 10ms\n            0x3f, 0x06,                         // window offset 2 sec\n            0x40, 0x06,                         // interval 2 sec\n            0x00, 0x00,                         // peripheral latency\n            0x48, 0x02,                         // connection timeout\n            0xff, 0xff, 0xff, 0xff, 0x1f,       // used channel map\n            0x2a                                // 1: sleep clock accuracy 151 ppm to 250 ppm\n        }\n    );\n\n    run();\n\n    BOOST_REQUIRE( !connection_events().empty() );\n\n    const auto& event = connection_events().front();\n\n    BOOST_CHECK( event.start_receive.usec() >= 1999300 -1 );\n    BOOST_CHECK( event.start_receive.usec() <= 1999300 +1 );\n    BOOST_CHECK( event.end_receive.usec() >= 2010703 -1 );\n    BOOST_CHECK( event.end_receive.usec() <= 2010703 +1 );\n    BOOST_CHECK_EQUAL( event.connection_interval.usec(), 2000000u );\n}\n\n/*\n * 4.5.2.: If the ACL connection is not established after 6 connection events,\n * it shall be considered lost. This enables fast termination of ACL connections that fail to establish.\n */\nBOOST_FIXTURE_TEST_CASE( there_should_be_5_receive_attempts_before_the_connecting_times_out, connecting )\n{\n    BOOST_CHECK_EQUAL( connection_events().size(), 6u );\n}\n\n/*\n * The default devie sleep clock accuracy is 500ppm, the centrals sca is 50ppm.\n * The last T0 was the reception of the connect request. The transmit window offset is\n * ( 11 + 1 ) * 1.25ms, the window size is 3 * 1.25 ms. So the window starts at:\n * 15ms - 15ms * 550ppm = 14992µs; the window ends at 18.75ms + 18.75ms * 550ppm = 18760µs\n *\n * The conenction interval is 30ms\n */\nBOOST_FIXTURE_TEST_CASE( window_widening_is_applied_with_every_receive_attempt, connecting )\n{\n    unsigned count = 0;\n\n    for ( const auto& ev: connection_events() )\n    {\n        unsigned start = 15000 + count * 30000;\n        unsigned end   = start + 3750;\n        ++count;\n\n        start -= start * 550 / 1000000;\n        end   += end * 550 / 1000000;\n\n        BOOST_CHECK_EQUAL( ev.start_receive.usec(), start );\n        BOOST_CHECK_EQUAL( ev.end_receive.usec(), end );\n    }\n}\n\nBOOST_FIXTURE_TEST_CASE( while_waiting_for_a_message_from_the_central_channels_are_hopped, connecting )\n{\n    std::vector< unsigned > expected_channels = { 10, 20, 30, 3, 13, 23 };\n    std::vector< unsigned > channels;\n\n    for ( const auto& ev: connection_events() )\n    {\n        channels.push_back( ev.channel );\n    }\n\n    BOOST_CHECK_EQUAL_COLLECTIONS( expected_channels.begin(), expected_channels.end(), channels.begin(), channels.end() );\n}\n\nBOOST_FIXTURE_TEST_CASE( again_advertising_after_the_connection_timeout_was_reached, connecting )\n{\n    // there must be an advertising pdu after the last connection event attempt\n    const auto last = connection_events().back().schedule_time;\n\n    BOOST_CHECK_GE( count_data(\n        [&last]( const test::advertising_data& adv )\n        {\n            return adv.schedule_time >= last;\n        } ), 1u );\n}\n\n\nBOOST_FIXTURE_TEST_CASE( no_connection_if_supervision_timeout_is_to_large, unconnected )\n{\n    respond_to(\n        37,\n        {\n            0xc5, 0x22,                         // header\n            0x3c, 0x1c, 0x62, 0x92, 0xf0, 0x48, // InitA: 48:f0:92:62:1c:3c (random)\n            0x47, 0x11, 0x08, 0x15, 0x0f, 0xc0, // AdvA:  c0:0f:15:08:11:47 (random)\n            0x5a, 0xb3, 0x9a, 0xaf,             // Access Address\n            0x08, 0x81, 0xf6,                   // CRC Init\n            0x03,                               // transmit window size\n            0x0b, 0x00,                         // window offset\n            0x18, 0x00,                         // interval\n            0x00, 0x00,                         // peripheral latency\n            0x81, 0x0c,                         // connection timeout\n            0xff, 0xff, 0xff, 0xff, 0x1f,       // used channel map\n            0xaa                                // hop increment and sleep clock accuracy\n        }\n    );\n\n    run();\n\n    check_not_connected( \"no_connection_if_supervision_timeout_is_to_large\" );\n}\n\nBOOST_FIXTURE_TEST_CASE( no_connection_if_supervision_timeout_is_smaller_than_10ms, unconnected )\n{\n    respond_to(\n        37,\n        {\n            0xc5, 0x22,                         // header\n            0x3c, 0x1c, 0x62, 0x92, 0xf0, 0x48, // InitA: 48:f0:92:62:1c:3c (random)\n            0x47, 0x11, 0x08, 0x15, 0x0f, 0xc0, // AdvA:  c0:0f:15:08:11:47 (random)\n            0x5a, 0xb3, 0x9a, 0xaf,             // Access Address\n            0x08, 0x81, 0xf6,                   // CRC Init\n            0x03,                               // transmit window size\n            0x0b, 0x00,                         // window offset\n            0x18, 0x00,                         // interval\n            0x00, 0x00,                         // peripheral latency\n            0x09, 0x00,                         // connection timeout\n            0xff, 0xff, 0xff, 0xff, 0x1f,       // used channel map\n            0xaa                                // hop increment and sleep clock accuracy\n        }\n    );\n\n    run();\n\n    check_not_connected( \"no_connection_if_supervision_timeout_is_smaller_than_10ms\" );\n}\n\n/*\n * with a peripheral latency of 5 and a interval of 30ms, the connection timeout shoule be\n * at least 6 * 30ms * 2 = 360ms\n */\nBOOST_FIXTURE_TEST_CASE( no_connection_if_supervision_timeout_is_to_small, unconnected )\n{\n    respond_to(\n        37,\n        {\n            0xc5, 0x22,                         // header\n            0x3c, 0x1c, 0x62, 0x92, 0xf0, 0x48, // InitA: 48:f0:92:62:1c:3c (random)\n            0x47, 0x11, 0x08, 0x15, 0x0f, 0xc0, // AdvA:  c0:0f:15:08:11:47 (random)\n            0x5a, 0xb3, 0x9a, 0xaf,             // Access Address\n            0x08, 0x81, 0xf6,                   // CRC Init\n            0x03,                               // transmit window size\n            0x0b, 0x00,                         // window offset\n            0x18, 0x00,                         // interval\n            0x05, 0x00,                         // peripheral latency\n            0x23, 0x00,                         // connection timeout 350ms\n            0xff, 0xff, 0xff, 0xff, 0x1f,       // used channel map\n            0xaa                                // hop increment and sleep clock accuracy\n        }\n    );\n\n    run();\n\n    check_not_connected( \"no_connection_if_supervision_timeout_is_to_small\" );\n}\n\nBOOST_FIXTURE_TEST_CASE( no_connection_if_peripheral_latency_is_larger_not_less_than_500, unconnected )\n{\n    respond_to(\n        37,\n        {\n            0xc5, 0x22,                         // header\n            0x3c, 0x1c, 0x62, 0x92, 0xf0, 0x48, // InitA: 48:f0:92:62:1c:3c (random)\n            0x47, 0x11, 0x08, 0x15, 0x0f, 0xc0, // AdvA:  c0:0f:15:08:11:47 (random)\n            0x5a, 0xb3, 0x9a, 0xaf,             // Access Address\n            0x08, 0x81, 0xf6,                   // CRC Init\n            0x03,                               // transmit window size\n            0x0b, 0x00,                         // window offset\n            0x18, 0x00,                         // interval\n            0xf4, 0x01,                         // peripheral latency\n            0x80, 0x0c,                         // connection timeout\n            0xff, 0xff, 0xff, 0xff, 0x1f,       // used channel map\n            0xaa                                // hop increment and sleep clock accuracy\n        }\n    );\n\n    run();\n\n    check_not_connected( \"no_connection_if_peripheral_latency_is_larger_not_less_than_500\" );\n}\n\nBOOST_FIXTURE_TEST_CASE( connection_established_when_window_offset_equals_interval, unconnected )\n{\n    respond_to(\n        37,\n        {\n            0xc5, 0x22,                         // header\n            0x3c, 0x1c, 0x62, 0x92, 0xf0, 0x48, // InitA: 48:f0:92:62:1c:3c (random)\n            0x47, 0x11, 0x08, 0x15, 0x0f, 0xc0, // AdvA:  c0:0f:15:08:11:47 (random)\n            0x5a, 0xb3, 0x9a, 0xaf,             // Access Address\n            0x08, 0x81, 0xf6,                   // CRC Init\n            0x03,                               // transmit window size\n            0x18, 0x00,                         // window offset\n            0x18, 0x00,                         // interval\n            0x00, 0x00,                         // peripheral latency\n            0x80, 0x0c,                         // connection timeout\n            0xff, 0xff, 0xff, 0xff, 0x1f,       // used channel map\n            0xaa                                // hop increment and sleep clock accuracy\n        }\n    );\n\n    run();\n\n    BOOST_REQUIRE( !connection_events().empty() );\n}\n\nusing server_with_empty_white_list = unconnected_base<\n    bluetoe::link_layer::white_list< 1u >,\n    test::buffer_sizes\n>;\n\nBOOST_FIXTURE_TEST_CASE( connect_with_white_list_beeing_empty, server_with_empty_white_list )\n{\n    respond_to(\n        37,\n        {\n            0xc5, 0x22,                         // header\n            0x3c, 0x1c, 0x62, 0x92, 0xf0, 0x48, // InitA: 48:f0:92:62:1c:3c (random)\n            0x47, 0x11, 0x08, 0x15, 0x0f, 0xc0, // AdvA:  c0:0f:15:08:11:47 (random)\n            0x5a, 0xb3, 0x9a, 0xaf,             // Access Address\n            0x08, 0x81, 0xf6,                   // CRC Init\n            0x03,                               // transmit window size\n            0x18, 0x00,                         // window offset\n            0x18, 0x00,                         // interval\n            0x00, 0x00,                         // peripheral latency\n            0x80, 0x0c,                         // connection timeout\n            0xff, 0xff, 0xff, 0xff, 0x1f,       // used channel map\n            0xaa                                // hop increment and sleep clock accuracy\n        }\n    );\n\n    run();\n\n    BOOST_REQUIRE( !connection_events().empty() );\n}\n\nstruct server_with_white_list : unconnected_base< bluetoe::link_layer::white_list< 1u >, test::buffer_sizes >\n{\n    server_with_white_list()\n    {\n        add_to_white_list(\n            bluetoe::link_layer::random_device_address( { 0x3c, 0x1c, 0x62, 0x92, 0xf0, 0x48 } ) );\n\n        connection_request_filter( true );\n    }\n};\n\nBOOST_FIXTURE_TEST_CASE( connecting_client_is_in_white_list, server_with_white_list )\n{\n    respond_to(\n        37,\n        {\n            0xc5, 0x22,                         // header\n            0x3c, 0x1c, 0x62, 0x92, 0xf0, 0x48, // InitA: 48:f0:92:62:1c:3c (random)\n            0x47, 0x11, 0x08, 0x15, 0x0f, 0xc0, // AdvA:  c0:0f:15:08:11:47 (random)\n            0x5a, 0xb3, 0x9a, 0xaf,             // Access Address\n            0x08, 0x81, 0xf6,                   // CRC Init\n            0x03,                               // transmit window size\n            0x18, 0x00,                         // window offset\n            0x18, 0x00,                         // interval\n            0x00, 0x00,                         // peripheral latency\n            0x80, 0x0c,                         // connection timeout\n            0xff, 0xff, 0xff, 0xff, 0x1f,       // used channel map\n            0xaa                                // hop increment and sleep clock accuracy\n        }\n    );\n\n    run();\n\n    BOOST_REQUIRE( !connection_events().empty() );\n}\n\nBOOST_FIXTURE_TEST_CASE( connecting_client_is_not_in_white_list, server_with_white_list )\n{\n    respond_to(\n        37,\n        {\n            0xc5, 0x22,                         // header\n            0x3c, 0x1c, 0x62, 0x92, 0xf0, 0x49, // InitA: 49:f0:92:62:1c:3c (random)\n            0x47, 0x11, 0x08, 0x15, 0x0f, 0xc0, // AdvA:  c0:0f:15:08:11:47 (random)\n            0x5a, 0xb3, 0x9a, 0xaf,             // Access Address\n            0x08, 0x81, 0xf6,                   // CRC Init\n            0x03,                               // transmit window size\n            0x18, 0x00,                         // window offset\n            0x18, 0x00,                         // interval\n            0x00, 0x00,                         // peripheral latency\n            0x80, 0x0c,                         // connection timeout\n            0xff, 0xff, 0xff, 0xff, 0x1f,       // used channel map\n            0xaa                                // hop increment and sleep clock accuracy\n        }\n    );\n\n    run();\n\n    BOOST_REQUIRE( connection_events().empty() );\n}\n"
  },
  {
    "path": "tests/link_layer/ll_connection_tests.cpp",
    "content": "#define BOOST_TEST_MODULE\n#include <boost/test/included/unit_test.hpp>\n\n#include \"connected.hpp\"\n#include \"buffer_io.hpp\"\n\nstruct only_one_pdu_from_central : unconnected\n{\n    only_one_pdu_from_central()\n    {\n        respond_to( 37, valid_connection_request_pdu );\n        add_connection_event_respond( { 1, 0 } );\n\n        run();\n    }\n\n};\n\n/*\n * The connection interval is 30ms, the centrals clock accuracy is 50ppm and the peripheral is configured with\n * the default of 500ppm (in sum 550ppm).\n * So the maximum derivation is 16µs\n */\nBOOST_FIXTURE_TEST_CASE( smaller_window_after_connected, only_one_pdu_from_central )\n{\n    BOOST_REQUIRE_GE( connection_events().size(), 1u );\n    auto event = connection_events()[ 1 ];\n\n    BOOST_CHECK_EQUAL( event.start_receive, bluetoe::link_layer::delta_time::usec( 30000 - 16 ) );\n    BOOST_CHECK_EQUAL( event.end_receive, bluetoe::link_layer::delta_time::usec( 30000 + 16 ) );\n}\n\n/*\n * For the second connection event, the derivation from the 2*30ms is 33µs (+ 1µs extra for rounding)\n */\nBOOST_FIXTURE_TEST_CASE( window_size_is_increasing_with_connection_event_timeouts, only_one_pdu_from_central )\n{\n    BOOST_REQUIRE_GE( connection_events().size(), 2u );\n    auto event = connection_events()[ 2 ];\n\n    BOOST_CHECK( event.start_receive >= bluetoe::link_layer::delta_time::usec( 60000 - 34 ) );\n    BOOST_CHECK( event.start_receive <= bluetoe::link_layer::delta_time::usec( 60000 - 32 ) );\n    BOOST_CHECK( event.end_receive >= bluetoe::link_layer::delta_time::usec( 60000 + 32 ) );\n    BOOST_CHECK( event.end_receive <= bluetoe::link_layer::delta_time::usec( 60000 + 34 ) );\n\n}\n\n/*\n * Once the link layer received a PDU from the central, the supervision timeout is in charge\n * In this example, the timeout is 720ms, the connection interval is 30ms, so the timeout is\n * reached after 24 connection intervals (that's the 25th schedule request).\n */\nBOOST_FIXTURE_TEST_CASE( supervision_timeout_is_in_charge, only_one_pdu_from_central )\n{\n    BOOST_CHECK_EQUAL( connection_events().size(), 25u );\n}\n\nvoid add_channel_map_request( unconnected& c, std::uint16_t instance, std::uint64_t map )\n{\n    c.ll_control_pdu( {\n        0x01,                                                   // LL_CHANNEL_MAP_IND\n        static_cast< std::uint8_t >( map >> 0 ),                // map\n        static_cast< std::uint8_t >( map >> 8 ),\n        static_cast< std::uint8_t >( map >> 16 ),\n        static_cast< std::uint8_t >( map >> 24 ),\n        static_cast< std::uint8_t >( map >> 32 ),\n        static_cast< std::uint8_t >( instance >> 0 ),           // instance\n        static_cast< std::uint8_t >( instance >> 8 )\n    } );\n}\n\nvoid add_empty_pdus( unconnected& c, unsigned count )\n{\n    c.add_empty_pdus( count );\n}\n\nvoid add_ll_timeouts( unconnected& c, unsigned count )\n{\n    c.add_ll_timeouts( count );\n}\n\ntemplate < std::uint16_t Instance = 6, std::uint64_t Map = 0x1555555555, unsigned EmptyPDUs = Instance + 2 >\nstruct setup_connect_and_channel_map_request_base : unconnected\n{\n    static_assert( Instance > 0, \"Instance > 0\" );\n\n    setup_connect_and_channel_map_request_base()\n    {\n        respond_to( 37, valid_connection_request_pdu );\n        add_channel_map_request( *this, Instance, Map );\n        add_empty_pdus( EmptyPDUs );\n    }\n\n};\n\ntemplate < std::uint16_t Instance = 6, std::uint64_t Map = 0x1555555555, unsigned EmptyPDUs = Instance + 2 >\nstruct connect_and_channel_map_request_base : setup_connect_and_channel_map_request_base< Instance, Map, EmptyPDUs >\n{\n    connect_and_channel_map_request_base()\n    {\n        this->run();\n    }\n};\n\nusing instance_in_past = connect_and_channel_map_request_base< 0xffff, 0x1555555555, 20 >;\n\n/*\n * When the instance is in the past, the peripheral should consider the connection to be lost.\n * The bluetoe behaviour is to go back and advertise.\n */\nBOOST_FIXTURE_TEST_CASE( channel_map_request_with_instance_in_past, instance_in_past )\n{\n    BOOST_CHECK_EQUAL( connection_events().size(), 1u );\n}\n\nBOOST_FIXTURE_TEST_CASE( channel_map_request_with_wrong_size, unconnected )\n{\n    respond_to( 37, valid_connection_request_pdu );\n\n    ll_control_pdu( {\n        0x01,                                                   // LL_CHANNEL_MAP_IND\n        0xff, 0xff, 0xff, 0xff, 0x00,                           // map\n        0, 8,                                                   // instance\n        0xaa                                                    // ups, too large\n    } );\n\n    ll_empty_pdu();                                             // the response is expected to this connection event\n\n    run();\n\n    static constexpr std::uint8_t expected_response[] = {\n        0x03, 0x02,             // ll header\n        0x07, 0x01\n    };\n\n    auto response = connection_events().at( 1u ).transmitted_data.front().data;\n    response.at( 0 ) &= 0x03;\n\n    BOOST_CHECK_EQUAL_COLLECTIONS( std::begin( response ), std::end( response ), std::begin( expected_response ), std::end( expected_response ) );\n}\n\nusing connect_and_channel_map_request = connect_and_channel_map_request_base<>;\n\n/*\n * In this test, the odd channels are removed in connection event number 6. 19 channels remain.\n */\nBOOST_FIXTURE_TEST_CASE( channel_map_request, connect_and_channel_map_request )\n{\n    static constexpr unsigned expected_hop_sequence[] = {\n        10, 20, 30, 3, 13, 23, // connection event 0-5\n        28, 6\n    };\n\n    for ( unsigned i = 0; i != sizeof( expected_hop_sequence ) / sizeof( expected_hop_sequence[ 0 ] ); ++i )\n    {\n        BOOST_CHECK_EQUAL( connection_events().at( i ).channel, expected_hop_sequence[ i ] );\n    }\n}\n\nusing setup_connect_and_channel_map_request = setup_connect_and_channel_map_request_base<>;\n\n/*\n * Make sure, that after a channel map request, the link layer still works as expected\n */\nBOOST_FIXTURE_TEST_CASE( link_layer_still_active_after_channel_map_request, setup_connect_and_channel_map_request )\n{\n    ll_control_pdu( { 0x12 } ); // this will be send within the 10th connection event\n    ll_empty_pdu();             // the response is expected to this connection event\n    run();\n\n    // and the response is send with the 11th event\n    BOOST_REQUIRE( !connection_events().at( 10 ).transmitted_data.empty() );\n    auto pdu = connection_events().at( 10 ).transmitted_data.front().data;\n    BOOST_REQUIRE( !pdu.empty() );\n    pdu[ 0 ] &= 0x3;\n\n    static constexpr std::uint8_t expected_response[] = { 0x03, 0x01, 0x13 };\n    BOOST_CHECK_EQUAL_COLLECTIONS( std::begin( pdu ), std::end( pdu ), std::begin( expected_response ), std::end( expected_response ) );\n}\n\nusing channel_map_request_with_one_timeout_fixture = setup_connect_and_channel_map_request_base< 5, 0x1000000001, 2 >;\n\n/*\n * This test should make sure that connEventCounter is incremented, event when an connection event timed out\n */\nBOOST_FIXTURE_TEST_CASE( channel_map_request_with_one_timeout, channel_map_request_with_one_timeout_fixture )\n{\n    add_connection_event_respond_timeout(); // event 3\n    ll_empty_pdu();\n    ll_empty_pdu();                         // event 5; here the map change is applied\n    ll_empty_pdu();\n\n    run();\n\n    static constexpr unsigned expected_hop_sequence[] = {\n        10, 20, 30, 3, 13, // connection event 0-4\n        36, 36\n    };\n\n    for ( unsigned i = 0; i != sizeof( expected_hop_sequence ) / sizeof( expected_hop_sequence[ 0 ] ); ++i )\n    {\n        BOOST_CHECK_EQUAL( connection_events().at( i ).channel, expected_hop_sequence[ i ] );\n    }\n}\n\n/*\n * This test should make sure that even when the map change is to be applied on an event, where a timeout\n * occures, that the map change is applied correctly\n */\nBOOST_FIXTURE_TEST_CASE( channel_map_request_within_timeout, channel_map_request_with_one_timeout_fixture )\n{\n    ll_empty_pdu(); // event 3\n    add_connection_event_respond_timeout();\n    ll_empty_pdu(); // event 5; here the map change is applied\n    ll_empty_pdu();\n\n    run();\n\n    static constexpr unsigned expected_hop_sequence[] = {\n        10, 20, 30, 3, 13, // connection event 0-4\n        36, 36\n    };\n\n    for ( unsigned i = 0; i != sizeof( expected_hop_sequence ) / sizeof( expected_hop_sequence[ 0 ] ); ++i )\n    {\n        BOOST_CHECK_EQUAL( connection_events().at( i ).channel, expected_hop_sequence[ i ] );\n    }\n}\n\nstruct channel_map_request_after_connection_count_wrap_fixture : unconnected\n{\n    channel_map_request_after_connection_count_wrap_fixture()\n    {\n        respond_to( 37, valid_connection_request_pdu );\n\n        add_empty_pdus( 0x10000 - 4 );\n        add_channel_map_request( *this, 2, 0x1000000001 );\n        add_empty_pdus( 8 );\n    }\n};\n\n#if 0\n#ifndef BLUETOE_EXCLUDE_SLOW_TESTS\n\n/*\n * This test should make sure the instance is correctly interpreted after the connect count wrapped from 0xffff to 0x0000\n */\nBOOST_FIXTURE_TEST_CASE( channel_map_request_after_connection_count_wrap, channel_map_request_after_connection_count_wrap_fixture )\n{\n    end_of_simulation( bluetoe::link_layer::delta_time::seconds( 3000 ) );\n    run();\n\n    BOOST_CHECK_EQUAL( connection_events().at( 0x10002 ).channel, 36u );\n    BOOST_CHECK_EQUAL( connection_events().at( 0x10003 ).channel, 36u );\n    BOOST_CHECK_EQUAL( connection_events().at( 0x10004 ).channel, 36u );\n}\n\n#endif\n#endif\n\nBOOST_FIXTURE_TEST_CASE( l2cap_data_during_channel_map_request_with_buffer_big_enough_for_two_pdus, only_one_pdu_from_central )\n{\n    /// @TODO implement\n}\n\nBOOST_FIXTURE_TEST_CASE( l2cap_data_during_channel_map_request_with_buffer_big_enough_for_only_one_pdus, only_one_pdu_from_central )\n{\n    /// @TODO implement\n}\n\n/*\n * connection update procedure with a \"instance\" in the past results in falling back to advertising\n */\nBOOST_FIXTURE_TEST_CASE( connection_update_in_the_past, unconnected )\n{\n    respond_to( 37, valid_connection_request_pdu );\n    add_connection_update_request( 5, 5, 40, 1, 200, 0x8002 );\n    add_empty_pdus( 5 );\n\n    run();\n\n    BOOST_CHECK_EQUAL( connection_events().size(), 1u );\n}\n\nstruct connected_and_valid_connection_update_request_with_peripheral_latency : unconnected\n{\n    connected_and_valid_connection_update_request_with_peripheral_latency()\n    {\n        respond_to( 37, valid_connection_request_pdu );\n        add_connection_update_request( 5, 6, 40, 1, 200, 6 );\n        add_empty_pdus( 20 );\n\n        run();\n    }\n};\n\nstruct connected_and_valid_connection_update_request : unconnected\n{\n    connected_and_valid_connection_update_request()\n    {\n        respond_to( 37, valid_connection_request_pdu );\n        add_connection_update_request( 5, 6, 40, 0, 200, 6 );\n        add_empty_pdus( 20 );\n\n        run();\n    }\n};\n\n/*\n * The cummulated sleep clock accuracies of central and peripheral is 550ppm (50ppm + 500ppm)\n * The old connection interval is 30ms\n */\nBOOST_FIXTURE_TEST_CASE( connection_update_correct_transmit_window, connected_and_valid_connection_update_request_with_peripheral_latency )\n{\n    // The first event happend is 0 on which the connection update is send, the second is 1, due to\n    // the outstanding acknowledgment, the third will then be at instance 3\n    auto const evt = connection_events()[ 6 ];\n\n    bluetoe::link_layer::delta_time window_start( 30000 + 7500 );\n    bluetoe::link_layer::delta_time window_end( 30000 + 7500 + 6250 );\n    window_start -= window_start.ppm( 550 );\n    window_end   += window_end.ppm( 550 );\n\n    BOOST_REQUIRE_LT( window_start, window_end );\n\n    BOOST_CHECK_EQUAL( evt.start_receive, window_start );\n    BOOST_CHECK_EQUAL( evt.end_receive, window_end );\n    BOOST_CHECK_EQUAL( evt.channel, 70u % 37u );\n}\n\n/*\n * The cummulated sleep clock accuracies of central and peripheral is 550ppm (50ppm + 500ppm)\n * The new connection interval is 50ms, the new peripheral latency is 1\n */\nBOOST_FIXTURE_TEST_CASE( connection_update_correct_interval_used_with_latency, connected_and_valid_connection_update_request_with_peripheral_latency )\n{\n    auto const evt = connection_events()[ 7 ];\n\n    const bluetoe::link_layer::delta_time event_start( 2 * 50000 );\n\n    BOOST_CHECK_EQUAL( evt.start_receive, event_start - event_start.ppm( 550 ) );\n    BOOST_CHECK_EQUAL( evt.end_receive, event_start + event_start.ppm( 550 ) );\n}\n\n/*\n * The cummulated sleep clock accuracies of central and peripheral is 550ppm (50ppm + 500ppm)\n * The new connection interval is 50ms, the new peripheral latency is still 0\n */\nBOOST_FIXTURE_TEST_CASE( connection_update_correct_interval_used, connected_and_valid_connection_update_request )\n{\n    auto const evt = connection_events()[ 7 ];\n\n    const bluetoe::link_layer::delta_time event_start( 50000 );\n\n    BOOST_CHECK_EQUAL( evt.start_receive, event_start - event_start.ppm( 550 ) );\n    BOOST_CHECK_EQUAL( evt.end_receive, event_start + event_start.ppm( 550 ) );\n}\n\n/*\n * The old connection timeout is 720ms, the new connection timeout is 250ms\n * The new connection interval is 50ms, so after 5 connection events with timeout, the connection is timed out.\n */\nBOOST_FIXTURE_TEST_CASE( connection_update_correct_timeout_used, unconnected )\n{\n    respond_to( 37, valid_connection_request_pdu );\n    add_connection_update_request( 5, 6, 40, 0, 25, 6 );\n    add_empty_pdus( 6 );\n    add_ll_timeouts( 10 );\n\n    run();\n\n    BOOST_CHECK_EQUAL( connection_events().size(), std::size_t{ 8 + 4 } );\n}\n\nstatic void simulate_connection_update_request(\n    unconnected& c, std::uint8_t win_size, std::uint16_t win_offset, std::uint16_t interval,\n    std::uint16_t latency, std::uint16_t timeout, std::uint16_t instance )\n{\n    c.respond_to( 37, valid_connection_request_pdu );\n    c.add_connection_update_request( win_size, win_offset, interval, latency, timeout, instance );\n    c.add_empty_pdus( 10 );\n\n    c.run();\n}\n\nBOOST_FIXTURE_TEST_CASE( connection_update_request_invalid_window_size, unconnected )\n{\n    simulate_connection_update_request( *this, 205, 6, 40, 1, 25, 6 );\n\n    BOOST_CHECK_EQUAL( connection_events().size(), 6u );\n}\n\nBOOST_FIXTURE_TEST_CASE( connection_update_request_window_size_0, unconnected )\n{\n    simulate_connection_update_request( *this, 5, 0, 40, 0, 25, 6 );\n\n    BOOST_CHECK_EQUAL( connection_events().size(), 16u );\n}\n\nBOOST_FIXTURE_TEST_CASE( connection_update_request_invalid_window_offset, unconnected )\n{\n    simulate_connection_update_request( *this, 5, 206, 40, 1, 25, 6 );\n\n    BOOST_CHECK_EQUAL( connection_events().size(), 6u );\n}\n\nBOOST_FIXTURE_TEST_CASE( connection_update_request_invalid_interval, unconnected )\n{\n    simulate_connection_update_request( *this, 5, 6, 3200, 1, 25, 6 );\n\n    BOOST_CHECK_EQUAL( connection_events().size(), 6u );\n}\n\nBOOST_FIXTURE_TEST_CASE( connection_update_request_invalid_latency, unconnected )\n{\n    simulate_connection_update_request( *this, 5, 6, 40, 500, 25, 6 );\n\n    BOOST_CHECK_EQUAL( connection_events().size(), 6u );\n}\n\nBOOST_FIXTURE_TEST_CASE( connection_update_request_invalid_timeout, unconnected )\n{\n    simulate_connection_update_request( *this, 5, 6, 40, 1, 3300, 6 );\n\n    BOOST_CHECK_EQUAL( connection_events().size(), 6u );\n}\n\nBOOST_FIXTURE_TEST_CASE( connection_update_request_invalid_instance, unconnected )\n{\n    simulate_connection_update_request( *this, 5, 6, 40, 1, 25, 1 );\n\n    BOOST_CHECK_EQUAL( connection_events().size(), 1u );\n}\n\n/*\n * Test starts by having a LL_CONNECTION_UPDATE_REQ and at the instants connection event,\n * the server does not send a PDU. The peripheral still have to maintain the connection and\n * have to listen for the central the next but one connection interval.\n *\n * The centrals clock accuracy is 50ppm and the peripheral is configured with\n * the default of 500ppm (in sum 550ppm).\n */\nBOOST_FIXTURE_TEST_CASE( connection_update_missing_central_pdu_at_instant, unconnected )\n{\n    respond_to( 37, valid_connection_request_pdu );\n    add_connection_update_request( 6, 3, 6, 66, 198, 6 );\n    add_empty_pdus( 5 );\n    add_connection_event_respond_timeout();\n    add_empty_pdus( 5 );\n\n    run();\n\n    const auto at_instant  = connection_events().at( 6 );\n    const auto next        = connection_events().at( 7 );\n\n    // Timeout at_instance\n    BOOST_REQUIRE( at_instant.transmitted_data.empty() && at_instant.received_data.empty() );\n\n    // transmitWindowSize   = 7.5ms\n    // transmitWindowOffset = 3.75ms\n    // connIntervalOLD      = 30ms\n    // connIntervalnew      = 7.5ms\n\n    // connIntervalOLD + transmitWindowOffset + connIntervalnew\n    bluetoe::link_layer::delta_time window_start( 3750 + 7500 + 30000 );\n    // connIntervalOLD + transmitWindowOffset + connIntervalnew + transmitWindowSize\n    bluetoe::link_layer::delta_time window_end = window_start + bluetoe::link_layer::delta_time( 7500 );\n\n    window_start -= window_start.ppm( 550 );\n    window_end   += window_end.ppm( 550 );\n\n    BOOST_REQUIRE_LT( window_start, window_end );\n\n    BOOST_CHECK_EQUAL( next.start_receive, window_start );\n    BOOST_CHECK_EQUAL( next.end_receive, window_end );\n}\n\nBOOST_FIXTURE_TEST_CASE( connection_update_missing_central_pdu_before_and_at_instant, unconnected )\n{\n    respond_to( 37, valid_connection_request_pdu );\n    add_connection_update_request( 6, 3, 6, 66, 198, 6 );\n    add_empty_pdus( 4 );\n    add_connection_event_respond_timeout();\n    add_connection_event_respond_timeout();\n    add_empty_pdus( 5 );\n\n    run();\n\n    const auto before      = connection_events().at( 5 );\n    const auto at_instant  = connection_events().at( 6 );\n    const auto behind      = connection_events().at( 7 );\n\n    // transmitWindowSize   = 7.5ms\n    // transmitWindowOffset = 3.75ms\n    // connIntervalOLD      = 30ms\n    // connIntervalnew      = 7.5ms\n\n    // the first missing connection event was scheduled at connIntervalOLD based on prior connection events\n    // ancor point.\n\n    // connIntervalOLD + transmitWindowOffset + connIntervalnew\n    bluetoe::link_layer::delta_time window_start( 30000 );\n    // connIntervalOLD + transmitWindowOffset + connIntervalnew + transmitWindowSize\n    bluetoe::link_layer::delta_time window_end = window_start;\n\n    BOOST_CHECK_EQUAL( before.start_receive, window_start - window_start.ppm( 550 ) );\n    BOOST_CHECK_EQUAL( before.end_receive, window_end + window_end.ppm( 550 ) );\n\n    // and timed out:\n    BOOST_REQUIRE( before.transmitted_data.empty() && before.received_data.empty() );\n\n    // the next connection event is then at the instant\n    window_start = bluetoe::link_layer::delta_time( 3750 + 30000 + 30000 );\n    window_end   = window_start + bluetoe::link_layer::delta_time( 7500 );\n\n    BOOST_CHECK_EQUAL( at_instant.start_receive, window_start - window_start.ppm( 550 ) );\n    BOOST_CHECK_EQUAL( at_instant.end_receive, window_end + window_end.ppm( 550 ) );\n\n    // the event after the missing event at instant is moved further by connIntervalnew\n    window_start += bluetoe::link_layer::delta_time( 7500 );\n    window_end   = window_start + bluetoe::link_layer::delta_time( 7500 );\n\n    BOOST_CHECK_EQUAL( behind.start_receive, window_start - window_start.ppm( 550 ) );\n    BOOST_CHECK_EQUAL( behind.end_receive, window_end + window_end.ppm( 550 ) );\n}\n\nBOOST_FIXTURE_TEST_CASE( response_to_an_feature_request, unconnected )\n{\n    respond_to( 37, valid_connection_request_pdu );\n    ll_control_pdu({\n        0x08,\n        0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00\n    });\n    ll_empty_pdu();\n\n    run();\n\n    auto response = connection_events().at( 1 ).transmitted_data.at( 0 );\n    response[ 0 ] &= 0x03;\n\n    static const std::uint8_t expected_response[] = {\n        0x03, 0x09,\n        0x09,\n        0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00\n    };\n\n    BOOST_CHECK_EQUAL_COLLECTIONS( std::begin( response ), std::end( response ), std::begin( expected_response ), std::end( expected_response ) );\n}\n"
  },
  {
    "path": "tests/link_layer/ll_control_tests.cpp",
    "content": "#define BOOST_TEST_MODULE\n#include <boost/test/included/unit_test.hpp>\n\n#include \"connected.hpp\"\n\nusing test::X;\nusing test::and_so_on;\n\nBOOST_FIXTURE_TEST_CASE( respond_with_an_unknown_rsp, unconnected )\n{\n    check_single_ll_control_pdu(\n        { 0x03, 0x01, 0xff },\n        {\n            0x03, 0x02,\n            0x07, 0xff\n        },\n        \"respond_with_an_unknown_rsp\"\n    );\n}\n\nBOOST_FIXTURE_TEST_CASE( respond_to_a_version_ind, unconnected )\n{\n    check_single_ll_control_pdu(\n        {\n            0x03, 0x06,\n            0x0C,               // LL_VERSION_IND\n            0x08,               // VersNr = Core Specification 4.2\n            0x00, 0x02,         // CompId\n            0x00, 0x00          // SubVersNr\n        },\n        {\n            0x03, 0x06,\n            0x0C,               // LL_VERSION_IND\n            0x09,               // VersNr = Core Specification 5.0\n            0x69, 0x02,         // CompId\n            0x00, 0x00          // SubVersNr\n        },\n        \"respond_to_a_version_ind\"\n    );\n}\n\n/**\n * LL/CON/PER/BI-15-C\n */\nBOOST_FIXTURE_TEST_CASE( respond_to_a_version_ind_ignoring_additional_requests, unconnected )\n{\n    this->respond_to( 37, valid_connection_request_pdu );\n    for ( int times = 0; times != 5; ++times )\n    {\n        ll_control_pdu({\n            0x0C,               // LL_VERSION_IND\n            0x08,               // VersNr = Core Specification 4.2\n            0x00, 0x02,         // CompId\n            0x00, 0x00          // SubVersNr\n        });\n    }\n    ll_empty_pdus( 4 );\n\n    run( 5 );\n\n    int num_responses = 0;\n\n    check_connection_events( [&]( const test::connection_event& evt ) -> bool\n    {\n        for ( const auto& response: evt.transmitted_data )\n        {\n            if ( check_pdu( response, { X, X, 0x0C, and_so_on } ) )\n                ++num_responses;\n        }\n\n        return true;\n    }, \"LL_VERSION_IND missing\" );\n\n    BOOST_CHECK_EQUAL( num_responses, 1 );\n}\n\nBOOST_FIXTURE_TEST_CASE( respond_to_a_ping, unconnected )\n{\n    check_single_ll_control_pdu(\n        {\n            0x03, 0x01,\n            0x12                // LL_PING_REQ\n        },\n        {\n            0x03, 0x01,\n            0x13                // LL_PING_RSP\n        },\n        \"respond_to_a_ping\"\n    );\n}\n\nBOOST_FIXTURE_TEST_CASE( starts_advertising_after_termination, unconnected )\n{\n    respond_to( 37, valid_connection_request_pdu );\n    add_connection_event_respond(\n        {\n            0x03, 0x02,\n            0x02, 0x12\n        } );\n\n    run();\n\n    // the second advertising PDU is the response to the terminate PDU\n    // and must happen much earlier than the supervision timeout\n    BOOST_REQUIRE_GT( advertisings().size(), 1u );\n    const auto& second_advertisment = advertisings()[ 1 ];\n\n    BOOST_CHECK_LT( second_advertisment.on_air_time, bluetoe::link_layer::delta_time::msec( 50 ) );\n}\n\nBOOST_FIXTURE_TEST_CASE( do_not_respond_to_UNKNOWN_RSP, unconnected )\n{\n    check_single_ll_control_pdu(\n        {\n            0x03, 0x02,\n            0x07,               // LL_UNKNOWN_RSP\n            0x07                // request opcode\n        },\n        {\n            0x01, 0x00\n        },\n        \"do_not_respond_to_UNKNOWN_RSP\"\n    );\n}\n\nBOOST_FIXTURE_TEST_CASE( do_not_respond_to_UNKNOWN_RSP_even_if_broken, unconnected )\n{\n    check_single_ll_control_pdu(\n        {\n            0x03, 0x03,\n            0x07,               // LL_UNKNOWN_RSP\n            0x07,               // request opcode\n            0xff                // additional byte\n        },\n        {\n            0x01, 0x00\n        },\n        \"do_not_respond_to_UNKNOWN_RSP\"\n    );\n}\n\n/*\n * Example from core spec Vol6, Part B, 5.1.2\n */\nBOOST_FIXTURE_TEST_CASE( Channel_Map_Update_procedure, unconnected )\n{\n    respond_to( 37, valid_connection_request_pdu );\n\n    ll_control_pdu(\n        {\n            0x01,                           // LL_CHANNEL_MAP_IND\n            0xff, 0xf7, 0xff, 0xff, 0x1f,   // new channel map: all channels enabled except channel 11\n            0x64, 0x00                      // Instance: 100dez\n        }\n    );\n\n    ll_empty_pdus( 101 );\n\n    run();\n\n    BOOST_CHECK_EQUAL( connection_events()[ 99 ].channel, 1u );\n    BOOST_CHECK_EQUAL( connection_events()[ 100 ].channel, 12u );\n    BOOST_CHECK_EQUAL( connection_events()[ 101 ].channel, 21u );\n}\n\nBOOST_FIXTURE_TEST_CASE( Channel_Map_Update_procedure_With_Latency, unconnected )\n{\n    respond_to( 37, {\n        0xc5, 0x22,                         // header\n        0x3c, 0x1c, 0x62, 0x92, 0xf0, 0x48, // InitA: 48:f0:92:62:1c:3c (random)\n        0x47, 0x11, 0x08, 0x15, 0x0f, 0xc0, // AdvA:  c0:0f:15:08:11:47 (random)\n        0x5a, 0xb3, 0x9a, 0xaf,             // Access Address\n        0x08, 0x81, 0xf6,                   // CRC Init\n        0x03,                               // transmit window size\n        0x0b, 0x00,                         // window offset\n        0x18, 0x00,                         // interval (30ms)\n        0x28, 0x00,                         // peripheral latency 40\n        0x48, 0x01,                         // connection timeout (3280ms)\n        0xff, 0xff, 0xff, 0xff, 0x1f,       // used channel map\n        0xaa                                // hop increment and sleep clock accuracy (10 and 50ppm)\n    } );\n\n    ll_control_pdu(\n        {\n            0x01,                           // LL_CHANNEL_MAP_IND\n            0xff, 0xf7, 0xff, 0xff, 0x1f,   // new channel map: all channels enabled except channel 11\n            0x64, 0x00                      // Instance: 100dez\n        }\n    );\n\n    ll_empty_pdus( 5 );\n\n    run();\n\n    // First event at instant 0; second at 41, third at 82; 4th at 100\n    BOOST_CHECK_EQUAL( connection_events()[ 3 ].channel, 12u );\n}\n\nstd::uint8_t notify_read_handler( std::size_t read_size, std::uint8_t* out_buffer, std::size_t& out_size );\n\nusing constantly_fireing_notifications_server =\n    bluetoe::server<\n        bluetoe::service<\n            bluetoe::service_uuid< 0x8C8B4094, 0x0DE2, 0x499F, 0xA28A, 0x4EED5BC73CA9 >,\n            bluetoe::characteristic<\n                bluetoe::characteristic_uuid< 0x8C8B4094, 0x0DE2, 0x499F, 0xA28A, 0x4EED5BC73CAA >,\n                bluetoe::free_read_handler< notify_read_handler >,\n                bluetoe::no_write_access,\n                bluetoe::notify\n            >\n        >,\n        bluetoe::no_gap_service_for_gatt_servers\n    >;\n\nstatic constantly_fireing_notifications_server* server_ptr = nullptr;\n\nstruct enable_notifications_t {\n    template < typename ConnectionData >\n    void ll_connection_established(\n          const bluetoe::link_layer::connection_details&   ,\n          const bluetoe::link_layer::connection_addresses& ,\n                ConnectionData&                            connection )\n    {\n        connection.client_configurations().flags( 0u, bluetoe::details::client_characteristic_configuration_notification_enabled );\n    }\n\n} enable_notifications;\n\nstruct constantly_fireing_notifications : unconnected_base_t<\n    constantly_fireing_notifications_server,\n    test::radio,\n    bluetoe::link_layer::connection_callbacks<\n        enable_notifications_t, enable_notifications\n    >\n>\n{\n    constantly_fireing_notifications()\n    {\n        this->respond_to( 37, valid_connection_request_pdu );\n\n        server_ptr = this;\n    }\n};\n\nstd::uint8_t notify_read_handler( std::size_t, std::uint8_t* out_buffer, std::size_t& out_size )\n{\n    *out_buffer = 42;\n    out_size = 1;\n\n    server_ptr->notify< bluetoe::characteristic_uuid< 0x8C8B4094, 0x0DE2, 0x499F, 0xA28A, 0x4EED5BC73CAA > >();\n\n    return bluetoe::error_codes::success;\n}\n\n/*\n * To not run into a procedure timeout, the link layer has to favor link layer responses over\n * GATT.\n */\nBOOST_FIXTURE_TEST_CASE( Favor_LL_Procedures_Over_Notifivations, constantly_fireing_notifications )\n{\n    static_assert( constantly_fireing_notifications::number_of_client_configs == 1, \"\" );\n\n    ll_empty_pdu();\n    ll_function_call([]{\n        BOOST_REQUIRE( ( server_ptr->notify< bluetoe::characteristic_uuid< 0x8C8B4094, 0x0DE2, 0x499F, 0xA28A, 0x4EED5BC73CAA > >() ) );\n    });\n    ll_control_pdu( {\n        0x12                // LL_PING_REQ\n    });\n    add_empty_pdus(10);\n\n    run(10);\n\n    bool ping_response_found = false;\n    int notification_found_cnt = 0;\n    bool ping_before_notification = false;\n\n    check_connection_events( [&]( const test::connection_event& evt ) -> bool {\n        using test::X;\n        using test::and_so_on;\n\n        for ( const auto& response: evt.transmitted_data )\n        {\n            ping_response_found = ping_response_found || check_pdu( response, { X, X, 0x13 } );\n            notification_found_cnt += check_pdu( response, { X, X, 0x04, 0x00, X, 0x00, 0x1b, and_so_on }) ? 1 : 0;\n\n            ping_before_notification = ping_before_notification\n                || ( ping_response_found && notification_found_cnt < 5);\n        }\n\n        return true;\n    }, \"LL_PING_RSP missing\" );\n\n    BOOST_CHECK( ping_response_found );\n    BOOST_CHECK_GT( notification_found_cnt, 10 );\n    BOOST_CHECK( ping_before_notification );\n}\n\nBOOST_AUTO_TEST_SUITE( disconnect )\n\n    template < typename ... Options >\n    struct default_connected : unconnected_base< Options... >\n    {\n        using base = unconnected_base< Options... >;\n\n        default_connected()\n        {\n            this->respond_to( 37, valid_connection_request_pdu );\n        }\n    };\n\n\n    BOOST_FIXTURE_TEST_CASE( local_disconnect_request, default_connected<> )\n    {\n        ll_function_call([&]{\n            this->disconnect();\n        });\n        ll_empty_pdu();\n\n        run();\n\n        int num_terminates = 0;\n\n        check_connection_events( [&]( const test::connection_event& evt ) -> bool\n        {\n            using test::X;\n            using test::and_so_on;\n\n            for ( const auto& response: evt.transmitted_data )\n            {\n                if ( !check_pdu( response, { X, 0 } ) )\n                {\n                    if ( !check_pdu( response, { X, 0x02, 0x02, 0x16 } ) )\n                        return false;\n\n                    ++num_terminates;\n                }\n            }\n\n            return true;\n        }, \"LL_TERMINATE_IND missing\" );\n\n        BOOST_CHECK_EQUAL( num_terminates, 1 );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( local_disconnect_requested_with_reason, default_connected<> )\n    {\n        ll_function_call([&]{\n            this->disconnect( 0x42 );\n        });\n        ll_empty_pdu();\n\n        run();\n\n        int num_terminates = 0;\n\n        check_connection_events( [&]( const test::connection_event& evt ) -> bool\n        {\n            using test::X;\n            using test::and_so_on;\n\n            for ( const auto& response: evt.transmitted_data )\n            {\n                if ( !check_pdu( response, { X, 0 } ) )\n                {\n                    if ( !check_pdu( response, { X, 0x02, 0x02, 0x42 } ) )\n                        return false;\n\n                    ++num_terminates;\n                }\n            }\n\n            return true;\n        }, \"LL_TERMINATE_IND missing\" );\n\n        BOOST_CHECK_EQUAL( num_terminates, 1 );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( local_disconnect_stop_sending_after_ack, default_connected<> )\n    {\n        ll_function_call([&]{\n            this->disconnect( 0x42 );\n        });\n        ll_empty_pdus(100);\n\n        end_of_simulation( bluetoe::link_layer::delta_time::seconds( 30 ) );\n        run();\n\n        BOOST_CHECK_LT( connection_events().back().start_receive,\n            bluetoe::link_layer::delta_time::msec( 100 ) );\n        BOOST_CHECK_LT( connection_events().size(), 4 );\n    }\n\n    template < class layout >\n    static void copy_air_to_mem( const std::vector< std::uint8_t >& over_the_air, bluetoe::link_layer::read_buffer& in_memory )\n    {\n        static constexpr std::size_t ll_header_size = 2;\n\n        const std::uint16_t header = bluetoe::details::read_16bit( over_the_air.data() );\n        const std::size_t   size   = std::min< std::size_t >( header >> 8, over_the_air.size() - ll_header_size );\n        const auto          body   = layout::body( in_memory );\n\n        layout::header( in_memory, header );\n        std::copy( over_the_air.data() + ll_header_size, over_the_air.data() + ll_header_size + size, body.first );\n\n        in_memory.size = layout::data_channel_pdu_memory_size( size );\n    }\n\n    struct disconnect_cb_t\n    {\n        bool disconnected;\n        std::uint8_t reason;\n\n        template < typename ConnectionData >\n        void ll_connection_closed( std::uint8_t r, ConnectionData& )\n        {\n            reason = r;\n            disconnected = true;\n        }\n\n    } disconnect_cb;\n\n    using connection_callbacks = unconnected_base<\n        bluetoe::link_layer::connection_callbacks< disconnect_cb_t, disconnect_cb >,\n        bluetoe::link_layer::no_auto_start_advertising\n    >;\n\n    static const bluetoe::link_layer::connection_event_events no_special_event;\n    static constexpr std::uint8_t sn   = 0x08;\n    static constexpr std::uint8_t nesn = 0x04;\n    static constexpr std::uint8_t llid = 0x01;\n\n    /**\n     * LL/CON/PER/BI-02-C\n     */\n    BOOST_FIXTURE_TEST_CASE( Peripheral_T_Terminate_Timer, connection_callbacks )\n    {\n        disconnect_cb.disconnected = false;\n\n        // currently, the test_radio ignores the SN and NESN of the simulation\n        // https://github.com/TorstenRobitzki/bluetoe/issues/134\n        // For now, simulation is done by calling the link_layer callbacks\n\n        // single call to run will cause the start of advertising\n        this->wake_up();\n        this->run();\n\n        bluetoe::link_layer::read_buffer connection_request = this->advertising_receive_buffer();\n        copy_air_to_mem< layout_t >( valid_connection_request_pdu, connection_request );\n        this->adv_received( connection_request );\n\n        // first connection event,\n        auto receive_buffer = this->allocate_receive_buffer();\n        copy_air_to_mem< layout_t >( { llid, 0x00 }, receive_buffer );\n        this->received( receive_buffer );\n        this->end_event( no_special_event );\n\n        // second connection event, transmitting the LL_TERMINATE_IND\n        this->disconnect( 0x13 );\n        receive_buffer = this->allocate_receive_buffer();\n        copy_air_to_mem< layout_t >( { llid | sn | nesn, 0x00 }, receive_buffer );\n        this->received( receive_buffer );\n        this->end_event( no_special_event );\n\n        // now, having connection events whithout acknowledging the transmitted LL_TERMINATE_IND\n        // interval is 30ms, timeout is 720ms (see definition of valid_connection_request_pdu)\n        for ( int i = 0; i != 23; ++i )\n        {\n            const std::uint8_t serial_num = i % 2 == 1 ? sn : 0;\n            // second connection event, NOT acknowledging the transmitted LL_TERMINATE_IND\n            receive_buffer = this->allocate_receive_buffer();\n            copy_air_to_mem< layout_t >( {\n                static_cast< std::uint8_t >( llid | serial_num | nesn ),\n                0x00 }, receive_buffer );\n            this->received( receive_buffer );\n            this->end_event( no_special_event );\n        }\n\n        BOOST_CHECK( disconnect_cb.disconnected );\n        BOOST_CHECK_EQUAL( disconnect_cb.reason, 0x22 );\n    }\n\n    /**\n     * LL/CON/PER/BI-02-C\n     *\n     * Same as above, make sure, that the disconnect happens, event when the\n     */\n    BOOST_FIXTURE_TEST_CASE( Peripheral_T_Terminate_Timer_With_Timeout, connection_callbacks )\n    {\n        disconnect_cb.disconnected = false;\n\n        this->wake_up();\n        this->run();\n\n        bluetoe::link_layer::read_buffer connection_request = this->advertising_receive_buffer();\n        copy_air_to_mem< layout_t >( valid_connection_request_pdu, connection_request );\n        this->adv_received( connection_request );\n\n        // first connection event,\n        auto receive_buffer = this->allocate_receive_buffer();\n        copy_air_to_mem< layout_t >( { llid, 0x00 }, receive_buffer );\n        this->received( receive_buffer );\n        this->end_event( no_special_event );\n\n        // second connection event, transmitting the LL_TERMINATE_IND\n        this->disconnect( 0x13 );\n        receive_buffer = this->allocate_receive_buffer();\n        copy_air_to_mem< layout_t >( { llid | sn | nesn, 0x00 }, receive_buffer );\n        this->received( receive_buffer );\n        this->end_event( no_special_event );\n\n        // now, having connection events whithout acknowledging the transmitted LL_TERMINATE_IND\n        // interval is 30ms, timeout is 720ms (see definition of valid_connection_request_pdu)\n        for ( int i = 0; i != 21; ++i )\n        {\n            const std::uint8_t serial_num = i % 2 == 1 ? sn : 0;\n            // second connection event, NOT acknowledging the transmitted LL_TERMINATE_IND\n            receive_buffer = this->allocate_receive_buffer();\n            copy_air_to_mem< layout_t >( {\n                static_cast< std::uint8_t >( llid | serial_num | nesn ),\n                0x00 }, receive_buffer );\n            this->received( receive_buffer );\n            this->end_event( no_special_event );\n        }\n\n        this->timeout();\n        this->timeout();\n\n        BOOST_CHECK( disconnect_cb.disconnected );\n        BOOST_CHECK_EQUAL( disconnect_cb.reason, 0x22 );\n    }\n\nBOOST_AUTO_TEST_SUITE_END()"
  },
  {
    "path": "tests/link_layer/ll_data_pdu_buffer_tests.cpp",
    "content": "#include <buffer_io.hpp>\n#include <bluetoe/ll_data_pdu_buffer.hpp>\n\n#define BOOST_TEST_MODULE\n#include <boost/test/included/unit_test.hpp>\n\n#include <initializer_list>\n#include <random>\n#include <tuple>\n#include <type_traits>\n\n#include \"buffer_io.hpp\"\n\nstatic bool radio_locked = false;\n\nclass lock_guard\n{\npublic:\n    lock_guard()\n    {\n        assert( !radio_locked );\n        radio_locked = true;\n    }\n\n    ~lock_guard()\n    {\n        radio_locked = false;\n    }\n\nprivate:\n    lock_guard( const lock_guard& ) = delete;\n    lock_guard& operator=( const lock_guard& ) = delete;\n};\n\ntemplate < std::size_t TransmitSize, std::size_t ReceiveSize >\nstruct mock_radio : bluetoe::link_layer::ll_data_pdu_buffer< TransmitSize, ReceiveSize, mock_radio< TransmitSize, ReceiveSize > > {\n    using lock_guard = ::lock_guard;\n\n    void increment_receive_packet_counter()\n    {\n        ++receive_packet_counter_;\n    }\n\n    void increment_transmit_packet_counter()\n    {\n        ++transmit_packet_counter_;\n    }\n\n    int receive_packet_counter() const\n    {\n        return receive_packet_counter_;\n    }\n\n    int transmit_packet_counter() const\n    {\n        return transmit_packet_counter_;\n    }\n\n    int receive_packet_counter_;\n    int transmit_packet_counter_;\n\n    mock_radio()\n        : receive_packet_counter_( 0 )\n        , transmit_packet_counter_( 0 )\n    {\n    }\n};\n\nusing buffer = mock_radio< 100, 100 >;\n\ntemplate < std::size_t TransmitSize, std::size_t ReceiveSize, template < std::size_t, std::size_t > class Radio >\nstruct running_mode_impl : Radio< TransmitSize, ReceiveSize >\n{\n    using layout = typename bluetoe::link_layer::pdu_layout_by_radio< Radio< TransmitSize, ReceiveSize > >::pdu_layout;\n\n    running_mode_impl()\n        : random( 42 ) // for testing, deterministic pseudo random is cool\n    {\n        this->reset_pdu_buffer();\n    }\n\n    template < class Iter >\n    void transmit_pdu( Iter begin, Iter end )\n    {\n        const std::size_t size = std::distance( begin, end );\n\n        auto buffer = this->allocate_transmit_buffer( layout::data_channel_pdu_memory_size( size ) );\n        assert( buffer.size == layout::data_channel_pdu_memory_size( size ) );\n\n        layout::header( buffer, 1 | ( size << 8 ) );\n\n        std::copy( begin, end, layout::body( buffer ).first );\n\n        this->commit_transmit_buffer( buffer );\n    }\n\n    void transmit_pdu( std::initializer_list< std::uint8_t > pdu )\n    {\n        transmit_pdu( std::begin( pdu ), std::end( pdu ) );\n    }\n\n    template < class Iter >\n    bluetoe::link_layer::write_buffer receive_pdu( Iter begin, Iter end, bool sn, bool nesn, std::uint8_t llid = 1 )\n    {\n        const auto size = std::distance( begin, end );\n        auto pdu = this->allocate_receive_buffer();\n\n        std::uint16_t header = llid | ( size << 8 );\n\n        if ( sn )\n            header |= 8;\n\n        if ( nesn )\n            header |= 4;\n\n        layout::header( pdu, header );\n        std::copy( begin, end, layout::body( pdu ).first );\n\n        return this->received( pdu );\n    }\n\n    bluetoe::link_layer::write_buffer receive_pdu( std::initializer_list< std::uint8_t > pdu, bool sn, bool nesn, std::uint8_t llid = 1 )\n    {\n        return receive_pdu( std::begin( pdu ), std::end( pdu ), sn, nesn, llid );\n    }\n\n    template < class Iter >\n    bluetoe::link_layer::write_buffer acknowledge_pdu( Iter begin, Iter end, bool sn, bool nesn )\n    {\n        const auto size = std::distance( begin, end );\n        auto pdu = this->allocate_receive_buffer();\n\n        std::uint16_t header = 1 | ( size << 8 );\n\n        if ( sn )\n            header |= 8;\n\n        if ( nesn )\n            header |= 4;\n\n        layout::header( pdu, header );\n        std::copy( begin, end, layout::body( pdu ).first );\n\n        return this->acknowledge( pdu );\n    }\n\n    bluetoe::link_layer::write_buffer acknowledge_pdu( std::initializer_list< std::uint8_t > pdu, bool sn, bool nesn )\n    {\n        return acknowledge_pdu( std::begin( pdu ), std::end( pdu ), sn, nesn );\n    }\n\n    std::vector< std::uint8_t > random_data( std::size_t s )\n    {\n        std::uniform_int_distribution< std::uint8_t > dist;\n\n        std::vector< std::uint8_t > result;\n\n        for ( ; s; --s )\n            result.push_back( dist( random ) );\n\n        return result;\n    }\n\n    std::size_t random_size()\n    {\n        std::uniform_int_distribution< std::uint8_t > dist( 1, this->max_rx_size() - 2 );\n        return dist( random );\n    }\n\n    std::size_t random_value( std::size_t begin, std::size_t end )\n    {\n        std::uniform_int_distribution< std::uint8_t > dist( begin, end );\n        return dist( random );\n    }\n\n    std::mt19937        random;\n};\n\nusing running_mode = running_mode_impl< 100, 100, mock_radio >;\n\nstruct one_element_in_transmit_buffer : running_mode\n{\n    one_element_in_transmit_buffer()\n    {\n       transmit_pdu( { 0x34 } );\n    }\n};\n\nconstexpr std::uint8_t simple_pdu[] = {\n    0x02, 0x04, 0x12, 0x34, 0x56, 0x78\n};\n\nBOOST_FIXTURE_TEST_CASE( raw_accessable_in_stopped_mode, buffer )\n{\n    BOOST_REQUIRE( raw_pdu_buffer() );\n\n    // if this doesn't cause a core dump, it's at least a hint that the access was valid\n    std::fill( raw_pdu_buffer(), raw_pdu_buffer() + size, 0 );\n}\n\nBOOST_FIXTURE_TEST_CASE( layout_overhead_is_zero, buffer )\n{\n    BOOST_CHECK_EQUAL( std::size_t{ layout_overhead }, 0u );\n}\n\nBOOST_FIXTURE_TEST_CASE( default_max_rx_size_is_29, buffer )\n{\n    BOOST_CHECK_EQUAL( max_rx_size(), 29u );\n}\n\nBOOST_FIXTURE_TEST_CASE( max_rx_size_can_be_changed, buffer )\n{\n    max_rx_size( 100u );\n    BOOST_CHECK_EQUAL( max_rx_size(), 100u );\n}\n\nBOOST_FIXTURE_TEST_CASE( max_rx_is_reset_to_29, buffer )\n{\n    max_rx_size( 100u );\n    reset_pdu_buffer();\n\n    BOOST_CHECK_EQUAL( max_rx_size(), 29u );\n}\n\nBOOST_FIXTURE_TEST_CASE( an_allocated_receive_buffer_must_be_max_rx_in_size, running_mode )\n{\n    const auto pdu = allocate_receive_buffer();\n    BOOST_CHECK_EQUAL( pdu.size, max_rx_size() );\n}\n\nBOOST_FIXTURE_TEST_CASE( default_max_tx_size_is_29, buffer )\n{\n    BOOST_CHECK_EQUAL( max_tx_size(), 29u );\n}\n\nBOOST_FIXTURE_TEST_CASE( max_tx_size_can_be_changed, buffer )\n{\n    max_tx_size( 100u );\n    BOOST_CHECK_EQUAL( max_tx_size(), 100u );\n}\n\nBOOST_FIXTURE_TEST_CASE( max_tx_is_reset_to_29, buffer )\n{\n    max_tx_size( 100u );\n    reset_pdu_buffer();\n\n    BOOST_CHECK_EQUAL( max_tx_size(), 29u );\n}\n\nBOOST_FIXTURE_TEST_CASE( an_allocated_transmit_buffer_must_be_max_tx_in_size, running_mode )\n{\n    const auto pdu = allocate_transmit_buffer();\n    BOOST_CHECK_EQUAL( pdu.size, max_tx_size() );\n}\n\n\nBOOST_FIXTURE_TEST_CASE( if_only_empty_pdus_are_received_the_buffer_will_never_overflow, running_mode )\n{\n    // 1/500 == never (by definition)\n    for ( int i = 0; i != 500; ++i )\n    {\n        const auto pdu = allocate_receive_buffer();\n        BOOST_REQUIRE( pdu.buffer );\n        BOOST_CHECK_GE( pdu.size, 2u );\n\n        pdu.buffer[ 0 ] = 1;\n        pdu.buffer[ 1 ] = 0;\n\n        received( pdu );\n    }\n}\n\nBOOST_FIXTURE_TEST_CASE( at_startup_the_receive_buffer_should_be_empty, running_mode )\n{\n    BOOST_CHECK_EQUAL( next_received().size, 0u );\n}\n\nBOOST_FIXTURE_TEST_CASE( at_startup_no_pending_transmit, running_mode )\n{\n    BOOST_CHECK( !pending_outgoing_data_available() );\n}\n\nstruct received_pdu : running_mode\n{\n    received_pdu()\n    {\n        const auto pdu = allocate_receive_buffer();\n        std::copy( std::begin( simple_pdu ), std::end( simple_pdu ), pdu.buffer );\n\n        received( pdu );\n    }\n\n};\n\nBOOST_FIXTURE_TEST_CASE( a_received_not_empty_pdu_is_accessable_from_the_link_layer, received_pdu )\n{\n    const auto received = next_received();\n\n    BOOST_CHECK_EQUAL_COLLECTIONS( std::begin( simple_pdu ), std::end( simple_pdu ), received.buffer, received.buffer + received.size );\n}\n\nBOOST_FIXTURE_TEST_CASE( if_half_buffer_size_is_used_as_max_rx_size_two_pdu_should_fit_into_the_buffer, running_mode )\n{\n    max_rx_size( max_max_rx_size() / 2 );\n\n    auto read = allocate_receive_buffer();\n    BOOST_CHECK_EQUAL( read.size, max_max_rx_size() / 2 );\n\n    // make buffer as used\n    read.buffer[ 1 ] = max_max_rx_size() / 2 - 2;\n    received( read );\n\n    BOOST_CHECK_EQUAL( allocate_receive_buffer().size, max_max_rx_size() / 2 );\n}\n\nBOOST_FIXTURE_TEST_CASE( if_buffer_size_is_used_as_max_rx_size_one_pdu_should_fit_into_the_buffer, running_mode )\n{\n    max_rx_size( max_max_rx_size() );\n\n    BOOST_CHECK_EQUAL( allocate_receive_buffer().size, max_max_rx_size() );\n}\n\n/*\n * verfiy, that a PDU with invalid LLID will be acknowledged, but ignored\n */\nBOOST_FIXTURE_TEST_CASE( LL_CON_PER_BI_17_C_ignore, running_mode )\n{\n    const auto response = receive_pdu( {\n        0x08,                       // LL_FEATURE_REQ\n        0xff, 0xff, 0xff, 0xff,\n        0xff, 0xff, 0xff, 0xff },\n        false,                      // SN\n        false,                      // NESN\n        0                           // LLID = invalid\n    );\n\n    BOOST_REQUIRE( response.size != 0 );\n    const std::uint16_t header = layout::header( response );\n\n    BOOST_CHECK_EQUAL( header & 0x04, 0x04 );\n    BOOST_CHECK_EQUAL( header & 0x08, 0x00 );\n}\n\n/*\n * verfiy, that a PDU with invalid LLID can acknowledge a transmitted PDU,\n * but will be ignored\n */\nBOOST_FIXTURE_TEST_CASE( LL_CON_PER_BI_17_C_ackn, running_mode )\n{\n    transmit_pdu( { 0xff } );\n\n    // first PDU is used to send the PDU about as a response\n    const auto transmit1 = receive_pdu(\n        {},                         // empty\n        false,                      // SN\n        false,                      // NESN\n        1                           // LLID = Empty PDU\n    );\n\n    BOOST_REQUIRE( transmit1.size != 0 );\n    const std::uint16_t transmit1_header = layout::header( transmit1 );\n    BOOST_CHECK_EQUAL( transmit1_header >> 8, 1 );\n\n    // second PDU has to acknowledge the send out PDU\n    const auto transmit2 = receive_pdu( {\n        0x08,                       // LL_FEATURE_REQ\n        0xff, 0xff, 0xff, 0xff,\n        0xff, 0xff, 0xff, 0xff },\n        true,                       // SN\n        true,                       // NESN\n        0                           // LLID = invalid\n    );\n\n    BOOST_REQUIRE( transmit2.size != 0 );\n    const std::uint16_t transmit2_header = layout::header( transmit2 );\n    BOOST_CHECK_EQUAL( transmit2_header >> 8, 0 );\n}\n\nBOOST_FIXTURE_TEST_SUITE( move_random_data_through_the_buffer, running_mode )\n\ntemplate < std::size_t V >\nusing intt = std::integral_constant< std::size_t, V >;\n\nusing test_sizes = std::tuple<\n    //          max_rx_size  min payload  max payload\n    std::tuple< intt< 29 >,  intt< 1 >,   intt< 25 > >,\n    std::tuple< intt< 50 >,  intt< 1 >,   intt< 48 > >,\n    std::tuple< intt< 29 >,  intt< 1 >,   intt< 1 > >,\n    std::tuple< intt< 29 >,  intt< 0 >,   intt< 25 > >,\n    std::tuple< intt< 29 >,  intt< 25 >,  intt< 25 > >\n>;\n\nBOOST_AUTO_TEST_CASE_TEMPLATE( move_random_data_through_the_buffer, sizes, test_sizes )\n{\n    std::vector< std::uint8_t >   test_data = this->random_data( 20 );\n    std::vector< std::uint8_t >   received_data;\n    std::vector< std::size_t >    transmit_sizes;\n    std::vector< std::size_t >    receive_sizes;\n\n    const std::size_t max_rx_size_value = std::tuple_element< 0, sizes >::type::value;\n    const std::size_t min_size          = std::tuple_element< 1, sizes >::type::value;\n    const std::size_t max_size          = std::tuple_element< 2, sizes >::type::value;\n\n    max_rx_size( max_rx_size_value );\n\n    auto emergency_counter = 2 * test_data.size();\n    bool sequence_number   = false;\n\n    for ( std::size_t send_size = 0; send_size < test_data.size(); --emergency_counter )\n    {\n        BOOST_REQUIRE( emergency_counter );\n        auto read = allocate_receive_buffer();\n\n        // if there is room in the receive buffer, I allocate that memory and simulate a received PDU\n        if ( read.size )\n        {\n            const std::size_t size = std::min< std::size_t >( random_value( min_size, max_size ), test_data.size() - send_size );\n\n            if ( size != 0 )\n            {\n                transmit_sizes.push_back( size );\n            }\n\n            read.buffer[ 1 ] = size;\n            read.buffer[ 0 ] = 2;\n\n            if ( sequence_number )\n                read.buffer[ 0 ] |= 8;\n\n            sequence_number = !sequence_number;\n\n            std::copy( test_data.begin() + send_size, test_data.begin() + send_size + size, &read.buffer[ 2 ] );\n            received( read );\n\n            send_size += size;\n        }\n        // if there is no more room left, I simulate the receiving of an pdu\n        else\n        {\n            auto next = next_received();\n            BOOST_REQUIRE_NE( next.size, 0u );\n            BOOST_REQUIRE_NE( next.buffer[ 1 ], 0u );\n\n            receive_sizes.push_back( next.buffer[ 1 ] );\n            BOOST_REQUIRE_LE( receive_sizes.size(), transmit_sizes.size() );\n            BOOST_REQUIRE_EQUAL( receive_sizes.back(), transmit_sizes[ receive_sizes.size() - 1 ] );\n\n            received_data.insert( received_data.end(), &next.buffer[ 2 ], &next.buffer[ 2 ] + next.buffer[ 1 ] );\n            free_received();\n        }\n    }\n\n    for ( auto next = next_received(); next.size; next = next_received(), --emergency_counter )\n    {\n        BOOST_REQUIRE( emergency_counter );\n        receive_sizes.push_back( next.buffer[ 1 ] );\n        BOOST_REQUIRE_LE( receive_sizes.size(), transmit_sizes.size() );\n        BOOST_REQUIRE_EQUAL( receive_sizes.back(), transmit_sizes[ receive_sizes.size() - 1 ] );\n\n        received_data.insert( received_data.end(), &next.buffer[ 2 ], &next.buffer[ 2 ] + next.buffer[ 1 ] );\n        free_received();\n    }\n\n    BOOST_CHECK_EQUAL_COLLECTIONS( test_data.begin(), test_data.end(), received_data.begin(), received_data.end() );\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_FIXTURE_TEST_CASE( the_transmitbuffer_will_yield_an_empty_pdu_if_the_buffer_is_empty, running_mode )\n{\n    auto write = next_transmit();\n\n    BOOST_CHECK_EQUAL( write.size, 2u );\n    BOOST_CHECK_EQUAL( write.buffer[ 0 ] & 0x03, 1 );\n    BOOST_CHECK_EQUAL( write.buffer[ 1 ], 0u );\n}\n\nBOOST_FIXTURE_TEST_CASE( if_transmit_buffer_is_empty_mode_data_flag_is_not_set, running_mode )\n{\n    auto write = next_transmit();\n\n    BOOST_CHECK_EQUAL( write.buffer[ 0 ] & 0x10, 0 );\n}\n\nBOOST_FIXTURE_TEST_CASE( as_long_as_an_pdu_is_not_acknowlaged_it_will_be_retransmited, one_element_in_transmit_buffer )\n{\n    for ( int i = 0; i != 3; ++i )\n    {\n        auto trans = next_transmit();\n        BOOST_REQUIRE_EQUAL( trans.size, 3u );\n        BOOST_CHECK_EQUAL( trans.buffer[ 1 ], 1u );\n        BOOST_CHECK_EQUAL( trans.buffer[ 2 ], 0x34u );\n    }\n}\n\nBOOST_FIXTURE_TEST_CASE( sequence_number_and_next_sequence_number_must_be_0_for_the_first_empty_pdu, one_element_in_transmit_buffer )\n{\n    auto write = next_transmit();\n\n    BOOST_CHECK_EQUAL( write.buffer[ 0 ] & 0x4, 0 );\n    BOOST_CHECK_EQUAL( write.buffer[ 0 ] & 0x8, 0 );\n}\n\nBOOST_FIXTURE_TEST_CASE( sequence_number_and_next_sequence_number_must_be_0_for_the_first_pdu, one_element_in_transmit_buffer )\n{\n    auto write = next_transmit();\n\n    BOOST_CHECK_EQUAL( write.buffer[ 0 ] & 0x4, 0 );\n    BOOST_CHECK_EQUAL( write.buffer[ 0 ] & 0x8, 0 );\n}\n\nBOOST_FIXTURE_TEST_CASE( only_one_transmitbuffer_entry_allocatable, running_mode )\n{\n    max_tx_size( 100 );\n\n    auto write1 = allocate_transmit_buffer();\n    write1.buffer[ 0 ] = 0;\n    write1.buffer[ 1 ] = 98;\n    commit_transmit_buffer( write1 );\n\n    auto write2 = allocate_transmit_buffer();\n    BOOST_CHECK_EQUAL( write2.size, 0u );\n}\n\nBOOST_FIXTURE_TEST_CASE( more_data_flag_is_not_set_if_only_one_element_is_in_the_transmit_buffer, one_element_in_transmit_buffer )\n{\n    auto write = next_transmit();\n    BOOST_CHECK_EQUAL( write.buffer[ 0 ] & 0x10, 0 );\n}\n\nBOOST_FIXTURE_TEST_CASE( more_data_flag_is_set_if_there_is_more_than_one_element_in_the_transmit_buffer, one_element_in_transmit_buffer )\n{\n    transmit_pdu( { 0x01 } );\n\n    auto transmit = next_transmit();\n    BOOST_CHECK_EQUAL( transmit.buffer[ 0 ] & 0x10, 0x10 );\n}\n\nBOOST_FIXTURE_TEST_CASE( more_data_flag_is_added_if_pdu_is_added, running_mode )\n{\n    // empty PDU without MD flag\n    auto first = next_transmit();\n    BOOST_CHECK_EQUAL( first.buffer[ 0 ] & 0x10, 0 );\n\n    transmit_pdu( { 0x01, 0x02, 0x03, 0x04 } );\n\n    auto next = next_transmit();\n\n    // must be the same PDU, as it was not acknowladged\n    BOOST_CHECK_EQUAL_COLLECTIONS( &first.buffer[ 2 ], &first.buffer[ first.size ], &next.buffer[ 2 ], &next.buffer[ next.size ] );\n\n    // sequence numbers and LLID must be equal\n    BOOST_CHECK_EQUAL( first.buffer[ 0 ] & 0xf, first.buffer[ 0 ] & 0xf );\n}\n\nBOOST_FIXTURE_TEST_CASE( a_new_pdu_will_be_transmitted_if_the_last_was_acknowladged, running_mode )\n{\n    transmit_pdu( { 1 } );\n    transmit_pdu( { 2 } );\n    transmit_pdu( { 3 } );\n    transmit_pdu( { 4 } );\n\n    BOOST_CHECK_EQUAL( next_transmit().buffer[ 2 ], 1u );\n    BOOST_CHECK_EQUAL( next_transmit().buffer[ 2 ], 1u );\n\n    // incomming PDU acknowledges\n    auto incomming = allocate_receive_buffer();\n    incomming.buffer[ 0 ] = 1 | 4;\n    incomming.buffer[ 1 ] = 0;\n    received( incomming );\n\n    // now the next pdu to be transmitted\n    BOOST_CHECK_EQUAL( next_transmit().buffer[ 2 ], 2u );\n\n    // next incomming PDU acknowledges, this time with NESN = 0\n    incomming = allocate_receive_buffer();\n    incomming.buffer[ 0 ] = 1;\n    incomming.buffer[ 1 ] = 25;\n    received( incomming );\n\n    // now the next pdu to be transmitted\n    BOOST_CHECK_EQUAL( next_transmit().buffer[ 2 ], 3u );\n}\n\nBOOST_FIXTURE_TEST_CASE( pending_transmit_pdu_is_oberservable, running_mode )\n{\n    transmit_pdu( { 1 } );\n    BOOST_CHECK( pending_outgoing_data_available() );\n\n    // incomming PDU acknowledges\n    auto incomming = allocate_receive_buffer();\n    incomming.buffer[ 0 ] = 1 | 4;\n    incomming.buffer[ 1 ] = 0;\n    received( incomming );\n\n    BOOST_CHECK( !pending_outgoing_data_available() );\n}\n\nBOOST_FIXTURE_TEST_CASE( received_pdu_with_LLID_0_is_ignored, running_mode )\n{\n    auto pdu = allocate_receive_buffer();\n    pdu.buffer[ 0 ] = 0;\n    pdu.buffer[ 1 ] = 1;\n\n    received( pdu );\n\n    BOOST_CHECK_EQUAL( next_received().size, 0u );\n}\n\nBOOST_FIXTURE_TEST_CASE( received_pdus_are_ignored_when_they_are_resent, running_mode )\n{\n    receive_pdu( { 1 }, false, false );\n    receive_pdu( { 2 }, false, false );\n\n    BOOST_CHECK_EQUAL( next_received().buffer[ 2 ], 1u );\n    free_received();\n\n    BOOST_CHECK_EQUAL( next_received().size, 0u );\n}\n\nBOOST_FIXTURE_TEST_CASE( with_every_new_received_pdu_a_new_sequence_is_expected, running_mode )\n{\n    BOOST_CHECK_EQUAL( next_transmit().buffer[ 0 ] & 0x4, 0 );\n\n    receive_pdu( { 1 }, false, false );\n    BOOST_CHECK_EQUAL( next_transmit().buffer[ 0 ] & 0x4, 0x4 );\n\n    receive_pdu( { 2 }, true, false );\n    BOOST_CHECK_EQUAL( next_transmit().buffer[ 0 ] & 0x4, 0 );\n}\n\nBOOST_FIXTURE_TEST_CASE( getting_an_empty_pdu_must_not_result_in_changing_allocated_transmit_buffer, running_mode )\n{\n    auto trans = allocate_transmit_buffer();\n    std::fill( trans.buffer, trans.buffer + trans.size, 0x22 );\n\n    // this call should not change the allocated buffer\n    next_transmit();\n\n    BOOST_CHECK( std::find_if( trans.buffer, trans.buffer + trans.size, []( std::uint8_t b ) { return b != 0x22; } ) == trans.buffer + trans.size );\n}\n\n// buffer with default sizes.\nstruct default_buffer : mock_radio< 3 * 29, 3 * 29 >\n{\n    default_buffer()\n    {\n        reset_pdu_buffer();\n        buffer = allocate_receive_buffer();\n    }\n\n    void receive_and_consume( std::initializer_list< std::uint8_t > pdu )\n    {\n        BOOST_REQUIRE_GE( buffer.size, pdu.size() );\n\n        std::copy( pdu.begin(), pdu.end(), buffer.buffer );\n        received( buffer );\n        buffer = allocate_receive_buffer();\n        BOOST_REQUIRE_GE( buffer.size, 29u );\n\n        if ( pdu.size() == 2 )\n        {\n            BOOST_CHECK( !next_received().size );\n        }\n        else\n        {\n            BOOST_CHECK( next_received().size );\n            free_received();\n        }\n\n        BOOST_CHECK( !next_received().size );\n    }\n\n    bluetoe::link_layer::read_buffer buffer;\n};\n\nBOOST_FIXTURE_TEST_CASE( receive_wrap_around, default_buffer )\n{\n    receive_and_consume( { 0x03, 0x06, 0x0c, 0x07, 0x0f, 0x00, 0x0d, 0x41 } );\n    receive_and_consume( { 0x0e, 0x07, 0x03, 0x00, 0x04, 0x00, 0x02 ,0x9e, 0x00 } );\n    receive_and_consume( { 0x01, 0x00 } );\n    receive_and_consume( { 0x0e, 0x0b, 0x07, 0x00, 0x04, 0x00, 0x10, 0x01, 0x00, 0xff, 0xff, 0x00, 0x28 } );\n    receive_and_consume( { 0x01, 0x00 } );\n    receive_and_consume( { 0x0e, 0x0b, 0x07, 0x00, 0x04, 0x00, 0x10, 0x05, 0x00, 0xff, 0xff, 0x00, 0x28 } );\n}\n\nnamespace changed_pdu_layout\n{\n    /*\n     * lets invert all bits in the header and use an extra byte in front and behind the payload\n     */\n    struct pdu_layout : bluetoe::link_layer::details::layout_base< pdu_layout > {\n\n        using bluetoe::link_layer::details::layout_base< pdu_layout >::header;\n\n        /**\n         * @brief returns the header for advertising channel and for data channel PDUs.\n         */\n        static std::uint16_t header( const std::uint8_t* pdu )\n        {\n            return bluetoe::details::read_16bit( pdu ) ^ 0xffff;\n        }\n\n        /**\n         * @brief writes to the header of the given PDU\n         */\n        static void header( std::uint8_t* pdu, std::uint16_t header_value )\n        {\n            bluetoe::details::write_16bit( pdu, header_value ^ 0xffff );\n        }\n\n        /**\n         * @brief returns the writable body for advertising channel or for data channel PDUs.\n         */\n        static std::pair< std::uint8_t*, std::uint8_t* > body( const bluetoe::link_layer::read_buffer& pdu )\n        {\n            return {\n                &pdu.buffer[ sizeof( std::uint16_t ) + 1 ],\n                &pdu.buffer[ pdu.size - 1 ]\n            };\n        }\n\n        /**\n         * @brief returns the readonly body for advertising channel or for data channel PDUs.\n         */\n        static std::pair< const std::uint8_t*, const std::uint8_t* > body( const bluetoe::link_layer::write_buffer& pdu )\n        {\n            return {\n                &pdu.buffer[ sizeof( std::uint16_t ) + 1 ],\n                &pdu.buffer[ pdu.size - 1 ]\n            };\n        }\n\n        static constexpr std::size_t data_channel_pdu_memory_size( std::size_t payload_size )\n        {\n            return sizeof( std::uint16_t ) + 2 + payload_size;\n        }\n    };\n\n    template < std::size_t TransmitSize, std::size_t ReceiveSize >\n    struct mock_radio : bluetoe::link_layer::ll_data_pdu_buffer< TransmitSize, ReceiveSize, mock_radio< TransmitSize, ReceiveSize > >\n    {\n        using lock_guard = ::lock_guard;\n\n        void increment_receive_packet_counter() {}\n\n        void increment_transmit_packet_counter() {}\n    };\n}\n\n/*\n * specialize pdu_layout_by_radio to apply the changed layout to the mocked radio\n */\nnamespace bluetoe\n{\n    namespace link_layer\n    {\n        template < std::size_t TransmitSize, std::size_t ReceiveSize >\n        struct pdu_layout_by_radio< changed_pdu_layout::mock_radio< TransmitSize, ReceiveSize > > {\n            using pdu_layout = changed_pdu_layout::pdu_layout;\n        };\n    }\n}\n\n/**\n * Tests to make sure, that the buffer is using the types and functions of the pdu_layout provided by the radio\n */\nBOOST_AUTO_TEST_SUITE( layout_tests )\n\n    using buffer_under_test = running_mode_impl< 31, 31, changed_pdu_layout::mock_radio >;\n    using large_buffer_under_test = running_mode_impl< 200, 200, changed_pdu_layout::mock_radio >;\n\n    BOOST_FIXTURE_TEST_CASE( make_sure_the_layout_is_used, buffer_under_test )\n    {\n        BOOST_CHECK( ( std::is_same< changed_pdu_layout::pdu_layout, layout >::value ) );\n        BOOST_CHECK_EQUAL( std::size_t{ layout_overhead }, 2u );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( default_buffer_sizes, buffer_under_test )\n    {\n        BOOST_CHECK_EQUAL( max_max_tx_size(), 29u );\n        BOOST_CHECK_EQUAL( max_tx_size(), 29u );\n        BOOST_CHECK_EQUAL( max_max_rx_size(), 29u );\n        BOOST_CHECK_EQUAL( max_rx_size(), 29u );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( default_large_buffer_sizes, large_buffer_under_test )\n    {\n        BOOST_CHECK_EQUAL( max_max_tx_size(), 198u );\n        BOOST_CHECK_EQUAL( max_tx_size(), 29u );\n        BOOST_CHECK_EQUAL( max_max_rx_size(), 198u );\n        BOOST_CHECK_EQUAL( max_rx_size(), 29u );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( lower_bound_sizes, large_buffer_under_test )\n    {\n        max_tx_size( 29 );\n        max_rx_size( 29 );\n        BOOST_CHECK_EQUAL( max_tx_size(), 29u );\n        BOOST_CHECK_EQUAL( max_rx_size(), 29u );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( upper_bound_sizes, large_buffer_under_test )\n    {\n        max_tx_size( 198 );\n        max_rx_size( 198 );\n        BOOST_CHECK_EQUAL( max_tx_size(), 198u );\n        BOOST_CHECK_EQUAL( max_rx_size(), 198u );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( allocating_lower_bound_buffers, large_buffer_under_test )\n    {\n        const auto receive  = allocate_receive_buffer();\n        const auto transmit = allocate_transmit_buffer();\n        BOOST_CHECK( receive.buffer );\n        BOOST_CHECK( transmit.buffer );\n        BOOST_CHECK_EQUAL( receive.size, 31u );\n        BOOST_CHECK_EQUAL( transmit.size, 31u );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( allocating_upper_bound_buffers, large_buffer_under_test )\n    {\n        max_tx_size( 198u );\n        max_rx_size( 198u );\n\n        const auto receive  = allocate_receive_buffer();\n        const auto transmit = allocate_transmit_buffer();\n        BOOST_CHECK( receive.buffer );\n        BOOST_CHECK( transmit.buffer );\n        BOOST_CHECK_EQUAL( receive.size, 200u );\n        BOOST_CHECK_EQUAL( transmit.size, 200u );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( make_sure_the_layout_is_applied_as_expected, buffer_under_test )\n    {\n        static const std::uint8_t pattern_a[] = { 'a', 'b', 'c', 'd', 'e' };\n        const std::size_t size = sizeof( pattern_a );\n\n        auto buffer = this->allocate_transmit_buffer( size + 4 );\n        BOOST_REQUIRE_EQUAL( buffer.size, size + 4 );\n\n        layout::header( buffer, 1 | ( size << 8 ) );\n\n        std::copy( std::begin( pattern_a ), std::end( pattern_a ), layout::body( buffer ).first );\n\n        // header at the begining\n        BOOST_CHECK_EQUAL( bluetoe::details::read_16bit( buffer.buffer ), 0xFAFE );\n\n        // body begins 1 byte behind the header and ends 1 byte before the end of the buffer\n        BOOST_CHECK( layout::body( buffer ).first == &buffer.buffer[ 3 ] );\n        BOOST_CHECK_EQUAL_COLLECTIONS(\n            std::begin( pattern_a ), std::end( pattern_a ),\n            &buffer.buffer[ 3 ], &buffer.buffer[ buffer.size - 1 ] );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( sending_data, buffer_under_test )\n    {\n        static const std::uint8_t pattern_a[] = { 'a', 'b', 'c', 'd', 'e' };\n\n        transmit_pdu( std::begin( pattern_a ), std::end( pattern_a ) );\n\n        auto transmit = next_transmit();\n\n        BOOST_CHECK_EQUAL( transmit.buffer[ 1 ] ^ 0xff , 5 );\n        BOOST_CHECK_EQUAL_COLLECTIONS(\n            std::begin( pattern_a ), std::end( pattern_a ),\n            &transmit.buffer[ 3 ], &transmit.buffer[ 3 + 5 ] );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( receiving_data, buffer_under_test )\n    {\n        static const std::uint8_t pattern_a[] = { 'a', 'b', 'c', 'd', 'e' };\n\n        receive_pdu( std::begin( pattern_a ), std::end( pattern_a ), false, true );\n\n        auto received = next_received();\n\n        BOOST_REQUIRE( received.size );\n        BOOST_CHECK_EQUAL( received.buffer[ 1 ] ^ 0xff , 5 );\n        BOOST_CHECK_EQUAL_COLLECTIONS(\n            std::begin( pattern_a ), std::end( pattern_a ),\n            &received.buffer[ 3 ], &received.buffer[ 3 + 5 ] );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( receiving_multiple_data, buffer_under_test )\n    {\n        static const std::uint8_t pattern_a[] = { 'a', 'b', 'c', 'd', 'e' };\n\n        receive_pdu( std::begin( pattern_a ), std::end( pattern_a ), false, true );\n\n        auto received = next_received();\n        BOOST_REQUIRE( received.size );\n\n        auto next_received = allocate_receive_buffer();\n        BOOST_REQUIRE( !next_received.size );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( receiving_multiple_data_large, large_buffer_under_test )\n    {\n        static const std::uint8_t pattern_a[] = { 'a', 'b', 'c', 'd', 'e' };\n        static const std::uint8_t pattern_b[] = { 'f', 'g', 'h', 'i', 'j' };\n\n        receive_pdu( std::begin( pattern_a ), std::end( pattern_a ), false, true );\n        receive_pdu( std::begin( pattern_b ), std::end( pattern_b ), false, true );\n\n        auto received = next_received();\n        BOOST_REQUIRE( received.size );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( acknowlage_send_data, buffer_under_test )\n    {\n        static const std::uint8_t pattern_a[] = { 'a', 'b', 'c', 'd', 'e' };\n\n        transmit_pdu( std::begin( pattern_a ), std::end( pattern_a ) );\n        BOOST_CHECK_EQUAL( next_transmit().size, 5u + 2u + 2u );\n        receive_pdu( std::begin( pattern_a ), std::end( pattern_a ), false, true );\n        BOOST_CHECK_EQUAL( next_transmit().size, 2u + 2u );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( not_acknowlage_send_data, buffer_under_test )\n    {\n        static const std::uint8_t pattern_a[] = { 'a', 'b', 'c', 'd', 'e' };\n\n        transmit_pdu( std::begin( pattern_a ), std::end( pattern_a ) );\n        BOOST_CHECK_EQUAL( next_transmit().size, 5u + 2u + 2u );\n        receive_pdu( std::begin( pattern_a ), std::end( pattern_a ), false, false );\n        BOOST_CHECK_EQUAL( next_transmit().size, 5u + 2u + 2u );\n    }\n\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE( packet_counter_tests )\n\n    BOOST_FIXTURE_TEST_CASE( do_not_increment_when_receiving_empty_pdu, running_mode )\n    {\n        receive_pdu( {}, false, false );\n        receive_pdu( {}, true, true );\n        BOOST_CHECK_EQUAL( receive_packet_counter(), 0 );\n    }\n\n    /*\n     * #102 if the master resends a not empty PDU, while the connection is encrypted,\n     *      the CRC of the received PDU is ok, but the MIC will not be ok, due to the\n     *      reused nonce.\n     *\n     *      In this case, the last PDU must be resend and the receive packet counter\n     *      must not be incremented.\n     */\n    BOOST_FIXTURE_TEST_CASE( do_not_increment_when_crc_is_ok_but_mic_is_not, running_mode )\n    {\n        receive_pdu( { 0x11 }, false, false );\n        BOOST_CHECK_EQUAL( receive_packet_counter(), 1 );\n        acknowledge_pdu( { 0x11 }, false, false );\n        BOOST_CHECK_EQUAL( receive_packet_counter(), 1 );\n    }\n\n    /*\n     * #102 When receiving a PDU with valid CRC but invalid MIC, last message has to\n     *      be repeated.\n     */\n    BOOST_FIXTURE_TEST_CASE( resend_when_crc_is_ok_but_mic_is_not, running_mode )\n    {\n        transmit_pdu( { 1 } );\n        BOOST_CHECK_EQUAL( transmit_packet_counter(), 0 );\n\n        receive_pdu( { 0x11 }, false, false );\n        BOOST_CHECK_EQUAL( receive_packet_counter(), 1 );\n\n        const auto pdu = acknowledge_pdu( { 0x11 }, false, false );\n        BOOST_CHECK_EQUAL( transmit_packet_counter(), 0 );\n        BOOST_CHECK_EQUAL( receive_packet_counter(), 1 );\n        BOOST_CHECK_EQUAL( pdu.size, 1u + 2u );\n\n        receive_pdu( { 0x22 }, true, true );\n        BOOST_CHECK_EQUAL( transmit_packet_counter(), 1 );\n        BOOST_CHECK_EQUAL( receive_packet_counter(), 2 );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( increment_when_receiving_none_empty_pdu, running_mode )\n    {\n        receive_pdu( { 0x11 }, false, false );\n        BOOST_CHECK_EQUAL( receive_packet_counter(), 1 );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( do_not_increment_when_receiving_unexpected_pdu, running_mode )\n    {\n        receive_pdu( { 0x11 }, false, false );\n        receive_pdu( { 0x11 }, false, true );\n        BOOST_CHECK_EQUAL( receive_packet_counter(), 1 );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( multiple_receive_increments, running_mode )\n    {\n        receive_pdu( { 0x11 }, false, false ); // increment\n        receive_pdu( { 0x11 }, true, false );  // increment\n        receive_pdu( {}, false, false );       // not incremented because it's empty\n        receive_pdu( { 0x11 }, true, false );  // increment\n        receive_pdu( { 0x11 }, true, false );  // not incremented because it's resend\n        BOOST_CHECK_EQUAL( receive_packet_counter(), 3 );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( do_not_increment_when_sending_empty_pdu, running_mode )\n    {\n        const auto empty1 = next_transmit();\n        static_cast< void >( empty1 );\n\n        // incomming PDU acknowledges\n        auto incomming = allocate_receive_buffer();\n        incomming.buffer[ 0 ] = 1 | 4;\n        incomming.buffer[ 1 ] = 0;\n        received( incomming );\n\n        BOOST_CHECK_EQUAL( transmit_packet_counter(), 0 );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( do_increment_when_send_pdu_was_acknowlaged, running_mode )\n    {\n        transmit_pdu( { 1 } );\n\n        BOOST_CHECK_EQUAL( transmit_packet_counter(), 0 );\n\n        // incomming PDU acknowledges\n        auto incomming = allocate_receive_buffer();\n        incomming.buffer[ 0 ] = 1 | 4;\n        incomming.buffer[ 1 ] = 0;\n        received( incomming );\n\n        BOOST_CHECK_EQUAL( transmit_packet_counter(), 1 );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( do_increment_when_resending_pdu, running_mode )\n    {\n        transmit_pdu( { 1 } );\n\n        BOOST_CHECK_EQUAL( transmit_packet_counter(), 0 );\n\n        // incomming PDU acknowledges\n        auto incomming = allocate_receive_buffer();\n        incomming.buffer[ 0 ] = 1;\n        incomming.buffer[ 1 ] = 0;\n        received( incomming );\n\n        transmit_pdu( { 1 } );\n\n        BOOST_CHECK_EQUAL( transmit_packet_counter(), 0 );\n    }\n\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE( stop_mode )\n\n    BOOST_FIXTURE_TEST_CASE( ignore_outgoing_pdus, running_mode )\n    {\n        // send out a single PDU\n        transmit_pdu( { 1 } );\n        stop_ll_pdu_buffer();\n\n        // not acknowledging the outgoing PDU\n        receive_pdu( {}, true, false );\n        receive_pdu( {}, false, false );\n\n        BOOST_CHECK( pending_outgoing_data_available() );\n\n        // adding a second PDU\n        transmit_pdu( { 2 } );\n\n        // acknowledging the first PDU\n        receive_pdu( {}, true, true );\n\n        // no pending PDU means, the second PDU was not stored\n        BOOST_CHECK( !pending_outgoing_data_available() );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( stop_reset, running_mode )\n    {\n        // send out a single PDU\n        transmit_pdu( { 1 } );\n        stop_ll_pdu_buffer();\n        reset_pdu_buffer();\n\n        // adding a second and third PDU\n        transmit_pdu( { 2 } );\n        transmit_pdu( { 3 } );\n\n        receive_pdu( {}, true, true );\n\n        // pending PDU means, the third PDU was not ignored\n        BOOST_CHECK( pending_outgoing_data_available() );\n    }\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "tests/link_layer/ll_data_tests.cpp",
    "content": "#define BOOST_TEST_MODULE\n#include <boost/test/included/unit_test.hpp>\n\n#include <bluetoe/link_layer.hpp>\n#include <bluetoe/server.hpp>\n\n#include \"test_radio.hpp\"\n#include \"test_servers.hpp\"\n#include \"connected.hpp\"\n\nBOOST_FIXTURE_TEST_CASE( response_to_att_request, unconnected )\n{\n    respond_to( 37, valid_connection_request_pdu );\n    ll_data_pdu(\n        {\n            0x03, 0x00,         // length\n            0x04, 0x00,         // Channel\n            0x02, 0x50, 0x00    // Exchange MTU Request\n        } );\n    ll_empty_pdu();\n\n    run();\n\n    auto response = connection_events().at( 1 ).transmitted_data.at( 0 );\n    response[ 0 ] &= 0x03;\n\n    static const std::uint8_t expected_response[] = {\n        0x02, 0x07,             // ll header\n        0x03, 0x00, 0x04, 0x00, // l2cap header\n        0x03, 0x17, 0x00        // Exchange MTU Response\n    };\n\n    BOOST_CHECK_EQUAL_COLLECTIONS( std::begin( response ), std::end( response ), std::begin( expected_response ), std::end( expected_response ) );\n}\n"
  },
  {
    "path": "tests/link_layer/ll_encryption_tests.cpp",
    "content": "#define BOOST_TEST_MODULE\n#include <boost/test/included/unit_test.hpp>\n\n#include \"connected.hpp\"\n#include <bluetoe/pairing_status.hpp>\n\nnamespace test {\n    std::uint16_t secret_value;\n\n    using secret_service = bluetoe::server<\n        bluetoe::service<\n            bluetoe::service_uuid< 0x8C8B4094, 0x0DE2, 0x499F, 0xA28A, 0x4EED5BC73CA9 >,\n            bluetoe::characteristic<\n                bluetoe::characteristic_uuid< 0x8C8B4094, 0x0DE2, 0x499F, 0xA28A, 0x4EED5BC73CAA >,\n                bluetoe::bind_characteristic_value< decltype( secret_value ), &secret_value >,\n                bluetoe::no_write_access\n            >,\n            bluetoe::requires_encryption\n        >\n    >;\n\n    // key, returned by find_key()\n    std::pair< bool, bluetoe::details::uint128_t > key_vault;\n    const bluetoe::details::uint128_t example_key = { {\n        0x01, 0x80, 0x02, 0x70,\n        0x03, 0x60, 0x04, 0x50,\n        0x05, 0x40, 0x06, 0x30,\n        0x07, 0x20, 0x08, 0x10\n    } };\n\n    std::uint16_t ediv;\n    std::uint64_t rand;\n\n    /**\n     * A mocked security manager to be used by the link_layer under test to\n     * easily fake the pairing state and the set of available keys.\n     */\n    struct security_manager\n    {\n        template < typename ... >\n        class impl\n        {\n        public:\n            template < class OtherConnectionData >\n            class channel_data_t : public OtherConnectionData\n            {\n            public:\n                std::pair< bool, bluetoe::details::uint128_t > find_key( std::uint16_t ediv, std::uint64_t rand ) const\n                {\n                    ::test::ediv = ediv;\n                    ::test::rand = rand;\n\n                    return key_vault;\n                }\n\n                void remote_connection_created( const bluetoe::link_layer::device_address& )\n                {\n                }\n\n                bluetoe::device_pairing_status local_device_pairing_status() const\n                {\n                    return bluetoe::device_pairing_status::no_key;\n                }\n\n                template < typename Connection >\n                void restore_bonded_cccds( Connection& )\n                {\n                }\n            };\n\n            template < class Connection >\n            void l2cap_input( const std::uint8_t*, std::size_t, std::uint8_t*, std::size_t&, Connection& )\n            {\n            }\n\n            template < class Connection >\n            bool security_manager_output_available( Connection& ) const\n            {\n                return false;\n            }\n\n            template < class Connection >\n            void l2cap_output( std::uint8_t*, std::size_t&, Connection& )\n            {\n            }\n\n            static constexpr std::uint16_t channel_id               = bluetoe::l2cap_channel_ids::sm;\n            static constexpr std::size_t   minimum_channel_mtu_size = bluetoe::details::default_att_mtu_size;\n            static constexpr std::size_t   maximum_channel_mtu_size = bluetoe::details::default_att_mtu_size;\n        };\n\n        struct meta_type :\n            bluetoe::details::security_manager_meta_type,\n            bluetoe::link_layer::details::valid_link_layer_option_meta_type {};\n    };\n}\n\nstruct link_layer_with_security : unconnected_base_t< test::secret_service, test::radio_with_encryption, test::security_manager, test::buffer_sizes >\n{\n\n    link_layer_with_security()\n    {\n        respond_to( 37, valid_connection_request_pdu );\n        test::key_vault = { false, { { 0x00 } } };\n        test::ediv      = 0u;\n        test::rand      = 0u;\n    }\n\n    void expected_response( const std::initializer_list< std::uint8_t >& expected_response, std::size_t event = 1, std::size_t pdu = 0 )\n    {\n        auto response = connection_events().at( event ).transmitted_data.at( pdu );\n        response[ 0 ] &= 0x03;\n\n        BOOST_CHECK_EQUAL_COLLECTIONS( std::begin( response ), std::end( response ), std::begin( expected_response ), std::end( expected_response ) );\n    }\n};\n\nBOOST_FIXTURE_TEST_CASE( response_to_an_feature_request_with_security_enabled, link_layer_with_security )\n{\n    ll_control_pdu({\n        0x08,\n        0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00\n    });\n    ll_empty_pdu();\n\n    run();\n\n    expected_response( {\n        0x03, 0x09,\n        0x09,\n        0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00\n    } );\n}\n\nBOOST_FIXTURE_TEST_CASE( skd_and_iv_stored, link_layer_with_security )\n{\n    ll_control_pdu({\n        0x03,                                   // LL_ENC_REQ\n        0x00, 0x11, 0x22, 0x33,                 // Rand\n        0x44, 0x55, 0x66, 0x77,\n        0x34, 0x12,                             // EDIV\n        0x00, 0x10, 0x20, 0x30,                 // SKDm\n        0x40, 0x50, 0x60, 0x70,\n        0xab, 0xbc, 0x12, 0x34,                 // IVm\n    });\n\n    run();\n\n    BOOST_CHECK_EQUAL( skdm(), 0x7060504030201000u );\n    BOOST_CHECK_EQUAL( ivm(), 0x3412bcabu );\n}\n\nBOOST_FIXTURE_TEST_CASE( ediv_and_rand_used, link_layer_with_security )\n{\n    ll_control_pdu({\n        0x03,                                   // LL_ENC_REQ\n        0x00, 0x11, 0x22, 0x33,                 // Rand\n        0x44, 0x55, 0x66, 0x77,\n        0x34, 0x12,                             // EDIV\n        0x00, 0x10, 0x20, 0x30,                 // SKDm\n        0x40, 0x50, 0x60, 0x70,\n        0xab, 0xbc, 0x12, 0x34,                 // IVm\n    });\n\n    run();\n\n    BOOST_CHECK_EQUAL( test::ediv, 0x1234u );\n    BOOST_CHECK_EQUAL( test::rand, 0x7766554433221100u );\n}\n\nBOOST_FIXTURE_TEST_CASE( still_unencrytped_after_IVs_exchanged, link_layer_with_security )\n{\n    ll_control_pdu({\n        0x03,                                   // LL_ENC_REQ\n        0x00, 0x11, 0x22, 0x33,                 // Rand\n        0x44, 0x55, 0x66, 0x77,\n        0x34, 0x12,                             // EDIV\n        0x00, 0x10, 0x20, 0x30,                 // SKDm\n        0x40, 0x50, 0x60, 0x70,\n        0xab, 0xbc, 0x12, 0x34,                 // IVm\n    });\n\n    run();\n\n    check_connection_events(\n        []( const test::connection_event& evt ) -> bool {\n            return !evt.receive_encryption_at_start_of_event\n                && !evt.transmit_encryption_at_start_of_event;\n        },\n        \"encrypted should not be enabled\"\n    );\n}\n\nBOOST_FIXTURE_TEST_CASE( encryption_request_unknown_long_term_key, link_layer_with_security )\n{\n    ll_control_pdu({\n        0x03,                                   // LL_ENC_REQ\n        0x00, 0x11, 0x22, 0x33,                 // Rand\n        0x44, 0x55, 0x66, 0x77,\n        0x34, 0x12,                             // EDIV\n        0x00, 0x10, 0x20, 0x30,                 // SKDm\n        0x40, 0x50, 0x60, 0x70,\n        0xab, 0xbc, 0x12, 0x34,                 // IVm\n    });\n    ll_empty_pdu();\n\n    run();\n\n    expected_response( {\n        0x03, 0x0d,\n        0x04,                                   // LL_ENC_RSP\n        0x56, 0xaa, 0x55, 0x78,                 // SKDm\n        0x10, 0x22, 0xac, 0x3f,\n        0x12, 0x34, 0x56, 0x78                  // IVm\n    } );\n\n    expected_response( {\n        0x03, 0x03,\n        0x11,                                   // LL_REJECT_IND_EXT\n        0x03,                                   // LL_ENC_REQ\n        0x06                                    // ErrorCode\n    }, 1, 1 );\n\n    check_connection_events(\n        []( const test::connection_event& evt ) -> bool {\n            return !evt.receive_encryption_at_start_of_event\n                && !evt.transmit_encryption_at_start_of_event;\n        },\n        \"encrypted should not be enabled\"\n    );\n}\n\nBOOST_FIXTURE_TEST_CASE( encryption_request_known_key, link_layer_with_security )\n{\n    test::key_vault = std::make_pair( true, test::example_key );\n\n    ll_control_pdu({\n        0x03,                                   // LL_ENC_REQ\n        0x00, 0x00, 0x00, 0x00,                 // Rand\n        0x00, 0x00, 0x00, 0x00,\n        0x00, 0x00,                             // EDIV\n        0x00, 0x10, 0x20, 0x30,                 // SKDm\n        0x40, 0x50, 0x60, 0x70,\n        0xab, 0xbc, 0x12, 0x34,                 // IVm\n    });\n    ll_empty_pdu();\n\n    run();\n\n    const auto used_key = encryption_key();\n    BOOST_CHECK_EQUAL_COLLECTIONS( std::begin( used_key ), std::end( used_key ), std::begin( test::example_key ), std::end( test::example_key ) );\n\n    expected_response( {\n        0x03, 0x0d,\n        0x04,                                   // LL_ENC_RSP\n        0x56, 0xaa, 0x55, 0x78,                 // SKDm\n        0x10, 0x22, 0xac, 0x3f,\n        0x12, 0x34, 0x56, 0x78                  // IVm\n    } );\n\n    expected_response( {\n        0x03, 0x01,\n        0x05                                    // LL_START_ENC_REQ\n    }, 1, 1 );\n\n    BOOST_CHECK( connection_events().at( 1 ).receive_encryption_at_start_of_event );\n\n    check_connection_events(\n        []( const test::connection_event& evt ) -> bool {\n            return !evt.transmit_encryption_at_start_of_event;\n        },\n        \"transmission should not be encrypted\"\n    );\n}\n\n/*\n  This is the \"start encryption\" example from the core spec (version 4.2); Vol. 6; Part C; 1\n\n    The following parameters are set to the fixed values below:\n    LTK = 0x4C68384139F574D836BCF34E9DFB01BF (MSO to LSO)\n    EDIV = 0x2474 (MSO to LSO)\n    RAND = 0xABCDEF1234567890 (MSO to LSO)\n    SKDm = 0xACBDCEDFE0F10213 (MSO to LSO)\n    SKDs = 0x0213243546576879 (MSO to LSO)\n    IVm = 0xBADCAB24 (MSO to LSO)\n    IVs = 0xDEAFBABE (MSO to LSO)\n\n */\nBOOST_FIXTURE_TEST_CASE( start_encryption_example, link_layer_with_security )\n{\n    static const bluetoe::details::uint128_t example_long_term_key = { {\n        0x4C, 0x68, 0x38, 0x41,\n        0x39, 0xF5, 0x74, 0xD8,\n        0x36, 0xBC, 0xF3, 0x4E,\n        0x9D, 0xFB, 0x01, 0xBF\n    } };\n\n    test::key_vault = std::make_pair( true, example_long_term_key );\n    setup_encryption_response( 0x0213243546576879, 0xDEAFBABE );\n\n    ll_control_pdu({\n        0x03,                                   // LL_ENC_REQ\n        0x90, 0x78, 0x56, 0x34,                 // Rand\n        0x12, 0xef, 0xcd, 0xab,\n        0x74, 0x24,                             // EDIV\n        0x13, 0x02, 0xf1, 0xe0,                 // SKDm\n        0xdf, 0xce, 0xbd, 0xac,\n        0x24, 0xab, 0xdc, 0xba                  // IVm\n    });\n    ll_empty_pdu();\n\n    run();\n\n    const auto used_key = encryption_key();\n    BOOST_CHECK_EQUAL_COLLECTIONS( std::begin( used_key ), std::end( used_key ), std::begin( example_long_term_key ), std::end( example_long_term_key ) );\n\n    expected_response( {\n        0x03, 0x0d,\n        0x04,                                   // LL_ENC_RSP\n        0x79, 0x68, 0x57, 0x46,                 // SKDm\n        0x35, 0x24, 0x13, 0x02,\n        0xbe, 0xba, 0xaf, 0xde                  // IVm\n    } );\n\n    expected_response( {\n        0x03, 0x01,\n        0x05                                    // LL_START_ENC_REQ\n    }, 1, 1 );\n\n    BOOST_CHECK( connection_events().at( 1 ).receive_encryption_at_start_of_event );\n\n    check_connection_events(\n        []( const test::connection_event& evt ) -> bool {\n            return !evt.transmit_encryption_at_start_of_event;\n        },\n        \"transmission should not be encrypted\"\n    );\n}\n\nstruct link_layer_with_encryption_setup : link_layer_with_security\n{\n    link_layer_with_encryption_setup()\n    {\n        test::key_vault = std::make_pair( true, test::example_key );\n\n        ll_control_pdu({\n            0x03,                                   // LL_ENC_REQ\n            0x00, 0x00, 0x00, 0x00,                 // Rand\n            0x00, 0x00, 0x00, 0x00,\n            0x00, 0x00,                             // EDIV\n            0x00, 0x10, 0x20, 0x30,                 // SKDm\n            0x40, 0x50, 0x60, 0x70,\n            0xab, 0xbc, 0x12, 0x34,                 // IVm\n        });\n        ll_empty_pdu();\n    }\n};\n\nBOOST_FIXTURE_TEST_CASE( start_encryption, link_layer_with_encryption_setup )\n{\n    ll_control_pdu({\n        0x06                                    // LL_START_ENC_RSP\n    });\n    ll_empty_pdu();\n\n    run();\n\n    expected_response( {\n        0x03, 0x01,\n        0x06                                    // LL_START_ENC_RSP\n    }, 3 );\n\n    BOOST_CHECK( connection_events().at( 1 ).receive_encryption_at_start_of_event );\n    BOOST_CHECK( connection_events().at( 3 ).transmit_encryption_at_start_of_event );\n}\n\nstruct link_layer_with_encryption : link_layer_with_encryption_setup\n{\n    link_layer_with_encryption()\n    {\n        ll_control_pdu({\n            0x06                                    // LL_START_ENC_RSP\n        });\n        ll_empty_pdu();\n    }\n};\n\nBOOST_FIXTURE_TEST_CASE( start_pause_encryption, link_layer_with_encryption )\n{\n    ll_control_pdu({\n        0x0A                                    // LL_PAUSE_ENC_REQ\n    });\n    ll_empty_pdu();\n\n    run();\n\n    expected_response( {\n        0x03, 0x01,\n        0x0B                                    // LL_PAUSE_ENC_RSP\n    }, 5 );\n\n    BOOST_CHECK( !connection_events().at( 5 ).receive_encryption_at_start_of_event );\n    BOOST_CHECK( connection_events().at( 5 ).transmit_encryption_at_start_of_event );\n}\n\nBOOST_FIXTURE_TEST_CASE( pause_encryption, link_layer_with_encryption )\n{\n    ll_control_pdu({\n        0x0A                                    // LL_PAUSE_ENC_REQ\n    });\n    ll_empty_pdu();\n\n    ll_control_pdu({\n        0x0B                                    // LL_PAUSE_ENC_RSP\n    });\n\n    run();\n\n    expected_response( {\n        0x03, 0x01,\n        0x0B                                    // LL_PAUSE_ENC_RSP\n    }, 5 );\n\n    BOOST_CHECK( !connection_events().at( 7 ).receive_encryption_at_start_of_event );\n    BOOST_CHECK( !connection_events().at( 7 ).transmit_encryption_at_start_of_event );\n}\n"
  },
  {
    "path": "tests/link_layer/ll_l2cap_sdu_buffer_tests.cpp",
    "content": "#define BOOST_TEST_MODULE\n#include <boost/test/included/unit_test.hpp>\n\n#include <bluetoe/ll_l2cap_sdu_buffer.hpp>\n\n#include \"test_layout.hpp\"\n\n#include <initializer_list>\n\nusing namespace boost::test_tools;\n\nnamespace {\n    class radio_mock_t\n    {\n    public:\n        radio_mock_t()\n            : available_transmit_buffers_( 0 )\n        {\n        }\n\n        static constexpr std::size_t header_size = 2;\n        static constexpr std::size_t layout_overhead = 1;\n\n        using layout = test::layout_with_overhead< layout_overhead >;\n\n        bluetoe::link_layer::read_buffer allocate_transmit_buffer( std::size_t size )\n        {\n            // allocate_transmit_buffer() is idempotent and thus should always return the\n            // same buffer.\n            if ( available_transmit_buffers_ == 0 )\n                return { nullptr, 0 };\n\n            assert( size <=\n                static_cast< std::size_t >( std::distance( std::begin( transmit_buffer_ ), std::end( transmit_buffer_ ) ) ) );\n\n            return { transmit_buffer_, size };\n        }\n\n        void commit_transmit_buffer( bluetoe::link_layer::read_buffer buffer )\n        {\n            tranmitted_pdus_.push_back( pdu_t( buffer.buffer, buffer.buffer + buffer.size ) );\n            assert( available_transmit_buffers_ > 0 );\n            --available_transmit_buffers_;\n        }\n\n        bluetoe::link_layer::write_buffer next_received() const\n        {\n            if ( received_pdus_.empty() )\n                return { nullptr, 0 };\n\n            auto& pdu = received_pdus_.front();\n\n            return { &pdu[ 0 ], pdu.size() };\n        }\n\n        void free_received()\n        {\n            BOOST_REQUIRE( !received_pdus_.empty() );\n            received_pdus_.erase( received_pdus_.begin() );\n        }\n\n        /*\n         * Interface for the tests\n         */\n        void add_received_pdu( std::initializer_list< std::uint8_t > incomming_pdu )\n        {\n            received_pdus_.push_back( pdu_t{ incomming_pdu.begin(), incomming_pdu.end() } );\n        }\n\n        bool receive_buffer_empty() const\n        {\n            return received_pdus_.empty();\n        }\n\n        void add_free_ll_pdus(std::size_t num_buffers)\n        {\n            available_transmit_buffers_ += num_buffers;\n        }\n\n        std::size_t max_tx_size() const\n        {\n            return 29 + layout_overhead;\n        }\n\n        std::vector< std::uint8_t > next_transmitted_pdu()\n        {\n            if ( tranmitted_pdus_.empty() )\n                return {};\n\n            const auto result = tranmitted_pdus_.front();\n            tranmitted_pdus_.erase( tranmitted_pdus_.begin() );\n\n            return result;\n        }\n\n        void fill_buffer( bluetoe::link_layer::read_buffer buffer, const std::initializer_list< std::uint8_t >& data )\n        {\n            assert( buffer.size >= data.size() );\n            std::copy( data.begin(), data.end(), buffer.buffer );\n        }\n\n        void pdu_receive_data_callback( const bluetoe::link_layer::write_buffer pdu )\n        {\n            received_data_pdus_.push_back( pdu_t( pdu.buffer, pdu.buffer + pdu.size ) );\n        }\n\n    private:\n        using pdu_t = std::vector< std::uint8_t >;\n        std::vector< pdu_t > received_pdus_;\n        std::size_t          available_transmit_buffers_;\n        std::vector< pdu_t > tranmitted_pdus_;\n        std::uint8_t         transmit_buffer_[256];\n        std::vector< pdu_t > received_data_pdus_;\n    };\n\n    class buffer_under_test : public bluetoe::link_layer::ll_l2cap_sdu_buffer< radio_mock_t, radio_mock_t, 100 >\n    {\n    public:\n        void expect_next_received( std::initializer_list< std::uint8_t > expected )\n        {\n            const auto received = next_ll_l2cap_received();\n\n            if ( received.size == 0 || received.buffer == nullptr || expected.size() == 0 )\n            {\n                BOOST_TEST( received.size == 0u );\n                BOOST_CHECK_EQUAL( static_cast< const void* >( received.buffer ), nullptr );\n                BOOST_TEST( expected.size() == 0u );\n            }\n            else\n            {\n                BOOST_CHECK_EQUAL_COLLECTIONS( received.buffer, received.buffer + received.size, expected.begin(), expected.end() );\n            }\n        }\n\n        void write_l2cap_size( bluetoe::link_layer::read_buffer buffer, std::size_t size )\n        {\n            bluetoe::details::write_16bit( layout::body( buffer ).first, size );\n        }\n    };\n}\n\n// All Tests are done with a layout that has an extra byte between header and body\nBOOST_AUTO_TEST_SUITE( receive_buffer_for_mtu_size_larger_than_23_bytes )\n\n    BOOST_FIXTURE_TEST_CASE( forward_empty_buffer, buffer_under_test )\n    {\n        expect_next_received( {} );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( link_layer_controll_pdus_are_directly_handed_from_the_radio, buffer_under_test )\n    {\n        add_received_pdu( { 0x03, 0x03, 0xaa, 0x01, 0x02, 0x03 } );\n\n        expect_next_received( { 0x03, 0x03, 0xaa, 0x01, 0x02, 0x03 } );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( small_l2cap_sdus_are_directly_handled_by_the_radio, buffer_under_test )\n    {\n        add_received_pdu( { 0x02, 0x08, 0xaa, 0x04, 0x00, 0xff, 0xff, 0x03, 0x01, 0x02, 0x03 } );\n\n        expect_next_received( { 0x02, 0x08, 0xaa, 0x04, 0x00, 0xff, 0xff, 0x03, 0x01, 0x02, 0x03 } );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( free_ll_l2cap_received_consumes_received_pdu, buffer_under_test )\n    {\n        add_received_pdu( { 0x02, 0x04, 0xaa, 0x00, 0x00, 0x00, 0x00 } );\n        expect_next_received( { 0x02, 0x04, 0xaa, 0x00, 0x00, 0x00, 0x00 } );\n\n        free_ll_l2cap_received();\n        expect_next_received( {} );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( too_small_l2cap_pdus_are_ignored, buffer_under_test )\n    {\n        add_received_pdu( { 0x02, 0x03, 0xaa, 0x00, 0x00 } );\n        expect_next_received( {} );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( fragmented_pdu_exceeds_maximum_mtu, buffer_under_test )\n    {\n        add_received_pdu(\n            {\n                0x02, 0x1B, 0xaa, 0x65, 0x00, 0x04, 0x00,       // Header: L2CAP length 24\n                0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // 23 bytes of data\n                0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,\n                0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27\n            }\n        );\n\n        add_received_pdu(\n            {\n                0x01, 0x1B, 0xaa,                               // Header: L2CAP length 24\n                0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // 27 bytes of data\n                0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,\n                0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,\n                0x31, 0x32, 0x33\n            }\n        );\n\n        add_received_pdu(\n            {\n                0x01, 0x1B, 0xaa,                               // Header: L2CAP length 24\n                0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // 27 bytes of data\n                0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,\n                0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,\n                0x31, 0x32, 0x33\n            }\n        );\n\n        add_received_pdu(\n            {\n                0x01, 0x18, 0xaa,                               // Header: L2CAP length 24\n                0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // 24 bytes of data\n                0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,\n                0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28\n            }\n        );\n\n        add_received_pdu( { 0x03, 0x03, 0xaa, 0x01, 0x02, 0x03 } );\n\n        expect_next_received( { 0x03, 0x03, 0xaa, 0x01, 0x02, 0x03 } );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( receiving_incomplete_fragmented_pdu, buffer_under_test )\n    {\n        add_received_pdu(\n            {\n                0x02, 0x1D, 0xaa, 0x18, 0x00, 0x04, 0x00,       // Header: L2CAP length 24\n                0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // 23 bytes of data\n                0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,\n                0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27\n            }\n        );\n\n        expect_next_received( {} );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( receiving_fragmented_pdu, buffer_under_test )\n    {\n        add_received_pdu(\n            {\n                0x02, 0x1D, 0xaa, 0x18, 0x00, 0x04, 0x00,       // Header: L2CAP length 24\n                0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // 23 bytes of data\n                0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,\n                0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27\n            }\n        );\n\n        add_received_pdu(\n            {\n                0x01, 0x01, 0xaa, 0x28                          // remaining byte\n            }\n        );\n\n        expect_next_received(\n            {\n                0x02, 0x1D, 0xaa, 0x18, 0x00, 0x04, 0x00,       // Header: L2CAP length 24\n                0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // 24 bytes of data\n                0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,\n                0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28\n            }\n        );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( receiving_fragmented_pdu_in_two_calls, buffer_under_test )\n    {\n        add_received_pdu(\n            {\n                0x02, 0x1D, 0xaa, 0x18, 0x00, 0x04, 0x00,       // Header: L2CAP length 24\n                0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // 23 bytes of data\n                0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,\n                0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27\n            }\n        );\n\n        // after the incomplete SDU was received, the buffer returns no SDU\n        expect_next_received({});\n\n        add_received_pdu(\n            {\n                0x01, 0x01, 0xaa, 0x28                          // remaining byte\n            }\n        );\n\n        expect_next_received(\n            {\n                0x02, 0x1D, 0xaa, 0x18, 0x00, 0x04, 0x00,       // Header: L2CAP length 24\n                0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // 24 bytes of data\n                0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,\n                0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28\n            }\n        );\n    }\n\n    struct received_24byte_fragmented_sdu : public buffer_under_test\n    {\n        received_24byte_fragmented_sdu()\n        {\n            add_received_pdu(\n                {\n                    0x02, 0x1D, 0xaa, 0x18, 0x00, 0x04, 0x00,       // Header: L2CAP length 24\n                    0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // 23 bytes of data\n                    0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,\n                    0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27\n                }\n            );\n\n            add_received_pdu(\n                {\n                    0x01, 0x01, 0xaa, 0x28                          // remaining byte\n                }\n            );\n        }\n    };\n\n    BOOST_FIXTURE_TEST_CASE( next_ll_l2cap_received_is_idempotent, received_24byte_fragmented_sdu )\n    {\n        expect_next_received(\n            {\n                0x02, 0x1D, 0xaa, 0x18, 0x00, 0x04, 0x00,       // Header: L2CAP length 24\n                0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // 24 bytes of data\n                0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,\n                0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28\n            }\n        );\n\n        expect_next_received(\n            {\n                0x02, 0x1D, 0xaa, 0x18, 0x00, 0x04, 0x00,       // Header: L2CAP length 24\n                0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // 24 bytes of data\n                0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,\n                0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28\n            }\n        );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( free_received_fragmented, received_24byte_fragmented_sdu )\n    {\n        free_ll_l2cap_received();\n        expect_next_received({});\n    }\n\n    BOOST_FIXTURE_TEST_CASE( receiving_after_fragmented_sdu, received_24byte_fragmented_sdu )\n    {\n        add_received_pdu( { 0x03, 0x03, 0xaa, 0x01, 0x02, 0x03 } );\n\n        expect_next_received(\n            {\n                0x02, 0x1D, 0xaa, 0x18, 0x00, 0x04, 0x00,       // Header: L2CAP length 24\n                0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // 24 bytes of data\n                0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,\n                0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28\n            }\n        );\n        free_ll_l2cap_received();\n\n        expect_next_received( { 0x03, 0x03, 0xaa, 0x01, 0x02, 0x03 } );\n        free_ll_l2cap_received();\n\n        expect_next_received( {} );\n\n    }\nBOOST_AUTO_TEST_SUITE_END()\n\n// All Tests are done with a layout that has an extra byte between header and body\nBOOST_AUTO_TEST_SUITE( transmit_l2cap_sdus )\n\n    BOOST_FIXTURE_TEST_CASE( allocating_buffer, buffer_under_test )\n    {\n        const auto buffer = allocate_l2cap_transmit_buffer( 50 );\n\n        BOOST_CHECK_EQUAL( buffer.size, 50u + 4u + 3u );\n        BOOST_CHECK( buffer.buffer != nullptr );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( allocating_min_buffer, buffer_under_test )\n    {\n        const auto buffer = allocate_l2cap_transmit_buffer( 0 );\n\n        BOOST_CHECK_EQUAL( buffer.size, 4u + 3u );\n        BOOST_CHECK( buffer.buffer != nullptr );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( allocating_max_buffer, buffer_under_test )\n    {\n        const auto buffer = allocate_l2cap_transmit_buffer( 100 );\n\n        BOOST_CHECK_EQUAL( buffer.size, 100u + 4u + 3u );\n        BOOST_CHECK( buffer.buffer != nullptr );\n\n        // touch every single byte to trigger the sanatizer\n        std::fill( buffer.buffer, buffer.buffer + buffer.size, 0x42 );\n    }\n\n    // if the l2cap SDU uses all available LL PDUs, allocating a LL\n    // PDU must fail\n    BOOST_FIXTURE_TEST_CASE( l2cap_sdu_can_not_fully_written_to_the_ll_buffer, buffer_under_test )\n    {\n        const auto buffer = allocate_l2cap_transmit_buffer( 100 );\n        write_l2cap_size( buffer, 100 );\n        commit_l2cap_transmit_buffer( buffer );\n\n        const auto buffer2 = allocate_ll_transmit_buffer( 30 );\n\n        BOOST_CHECK_EQUAL( buffer2.size, 0u );\n        BOOST_CHECK( buffer2.buffer == nullptr );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( l2cap_sdu_can_fully_written_to_the_ll_buffer, buffer_under_test )\n    {\n        add_free_ll_pdus(100);\n        const auto buffer = allocate_l2cap_transmit_buffer( 100 );\n        write_l2cap_size( buffer, 100 );\n        commit_l2cap_transmit_buffer( buffer );\n\n        const auto buffer2 = allocate_ll_transmit_buffer( 27 );\n\n        BOOST_CHECK_EQUAL( buffer2.size, 30u );\n        BOOST_CHECK( buffer2.buffer != nullptr );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( allocating_l2cap_buffer_is_possible_once_all_ll_pdus_are_written, buffer_under_test )\n    {\n        // With a PDU size of 30 (min 29 + 1 for the layout overheader), the 107 bytes are written in 4 chunks:\n        // 30, 27, 27, 23\n        add_free_ll_pdus(3);\n        const auto buffer = allocate_l2cap_transmit_buffer( 100 );\n        write_l2cap_size( buffer, 100 );\n        commit_l2cap_transmit_buffer( buffer );\n\n        // there is still one PDU missing to send the entire L2CAP SDU\n        BOOST_CHECK_EQUAL( allocate_ll_transmit_buffer( 27 ).size, 0u );\n        BOOST_CHECK_EQUAL( allocate_l2cap_transmit_buffer( 23 ).size, 0u );\n\n        // If the entire L2CAP SDU is written, the L2CAP buffer can be used again,\n        // but still no LL PDU available\n        add_free_ll_pdus(1);\n        BOOST_CHECK_EQUAL( allocate_ll_transmit_buffer( 27 ).size, 0u );\n        BOOST_CHECK_EQUAL( allocate_l2cap_transmit_buffer( 23 ).size, 30u );\n\n        add_free_ll_pdus(1);\n        BOOST_CHECK_EQUAL( allocate_ll_transmit_buffer( 27 ).size, 30u );\n        BOOST_CHECK_EQUAL( allocate_l2cap_transmit_buffer( 23 ).size, 30u );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( unfragmented_sdu, buffer_under_test )\n    {\n        add_free_ll_pdus(1);\n        const auto buffer = allocate_l2cap_transmit_buffer( 23 );\n        BOOST_REQUIRE( buffer.size == 30 );\n\n        fill_buffer( buffer, {\n            0x00, 0x00, 0x00,\n            0x17, 0x00, 0x04, 0x00,\n            0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,\n            0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,\n            0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26\n        } );\n\n        commit_l2cap_transmit_buffer( buffer );\n\n        BOOST_TEST( next_transmitted_pdu() == std::vector< std::uint8_t >({\n            0x02, 0x1B, 0x00,\n            0x17, 0x00, 0x04, 0x00,\n            0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,\n            0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,\n            0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26\n        }), per_element() );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( small_unfragmented_sdu, buffer_under_test )\n    {\n        add_free_ll_pdus(1);\n        const auto buffer = allocate_l2cap_transmit_buffer( 23 );\n        BOOST_REQUIRE( buffer.size == 30 );\n\n        fill_buffer( buffer, {\n            0x00, 0x00, 0x00,\n            0x08, 0x00, 0x04, 0x00,\n            0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07\n        } );\n\n        commit_l2cap_transmit_buffer( buffer );\n\n        BOOST_TEST( next_transmitted_pdu() == std::vector< std::uint8_t >({\n            0x02, 0x0C, 0x00,\n            0x08, 0x00, 0x04, 0x00,\n            0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07\n        }), per_element() );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( fragmented_sdu, buffer_under_test )\n    {\n        add_free_ll_pdus(2);\n        const auto buffer = allocate_l2cap_transmit_buffer( 100 );\n        BOOST_REQUIRE( buffer.size == 107);\n\n        fill_buffer( buffer, {\n            0x00, 0x00, 0x00,\n            0x48, 0x00, 0x04, 0x00,\n            0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,\n            0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,\n            0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,\n            0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,\n            0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,\n            0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,\n            0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,\n            0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,\n            0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87\n        } );\n\n        commit_l2cap_transmit_buffer( buffer );\n\n        BOOST_TEST( next_transmitted_pdu() == std::vector< std::uint8_t >({\n            0x02, 0x1B, 0x00,\n            0x48, 0x00, 0x04, 0x00,\n            0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,\n            0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,\n            0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26\n        }), per_element() );\n\n        BOOST_TEST( next_transmitted_pdu() == std::vector< std::uint8_t >({\n            0x01, 0x1B, 0x00,\n                                                      0x27,\n            0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,\n            0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,\n            0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,\n            0x60, 0x61\n        }), per_element() );\n\n        // transmitting stucked, because of no available transmit buffers in the radion\n        BOOST_TEST( next_transmitted_pdu() == std::vector< std::uint8_t >());\n\n        // make an addition transmit buffer available\n        add_free_ll_pdus(1);\n        // Next, when looking for new PDUs, the freed buffer is used to output\n        // the pending buffer\n        next_ll_l2cap_received();\n\n        BOOST_TEST( next_transmitted_pdu() == std::vector< std::uint8_t >({\n            0x01, 0x16, 0x00,\n                        0x62, 0x63, 0x64, 0x65, 0x66, 0x67,\n            0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,\n            0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87\n        }), per_element() );\n    }\n\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE( transmit_ll_pdus )\n\n    BOOST_FIXTURE_TEST_CASE( allocating_buffer, buffer_under_test )\n    {\n        add_free_ll_pdus(1);\n\n        const auto b1 = allocate_ll_transmit_buffer( 27 );\n        BOOST_CHECK_EQUAL( b1.size, 27u + 2u + 1u );\n\n        // allocate_ll_transmit_buffer is idempotent\n        const auto b2 = allocate_ll_transmit_buffer( 27 );\n        BOOST_CHECK_EQUAL( b2.size, 27u + 2u + 1u );\n\n        commit_ll_transmit_buffer( b2 );\n\n        const auto b3 = allocate_ll_transmit_buffer( 27 );\n        BOOST_CHECK_EQUAL( b3.size, 0u );\n    }\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "tests/link_layer/ll_notification_tests.cpp",
    "content": "#define BOOST_TEST_MODULE\n#include <boost/test/included/unit_test.hpp>\n\n#include <bluetoe/link_layer.hpp>\n\n#include \"connected.hpp\"\n\nstd::uint32_t temperature_value = 0;\n\nusing notify_server = bluetoe::server<\n        bluetoe::service<\n            bluetoe::service_uuid< 0x8C8B4094, 0x0DE2, 0x499F, 0xA28A, 0x4EED5BC73CA9 >,\n            bluetoe::characteristic<\n                bluetoe::characteristic_uuid< 0x8C8B4094, 0x0DE2, 0x499F, 0xA28A, 0x4EED5BC73CAA >,\n                bluetoe::bind_characteristic_value< decltype( temperature_value ), &temperature_value >,\n                bluetoe::no_write_access,\n                bluetoe::notify\n            >,\n            bluetoe::characteristic<\n                bluetoe::characteristic_uuid< 0x8C8B4094, 0x0DE2, 0x499F, 0xA28A, 0x4EED5BC73CAB >,\n                bluetoe::bind_characteristic_value< decltype( temperature_value ), &temperature_value >,\n                bluetoe::no_write_access,\n                bluetoe::indicate\n            >\n        >,\n        bluetoe::no_gap_service_for_gatt_servers\n    >;\n\nusing link_layer = unconnected_base_t< notify_server, test::radio >;\n\nBOOST_FIXTURE_TEST_CASE( request_cancelationen_when_notification_added, link_layer )\n{\n    const bool result = queue_lcap_notification(\n        bluetoe::details::notification_data( 2, 0 ), this, bluetoe::details::notification_type::notification );\n\n    BOOST_CHECK( result );\n    BOOST_CHECK( event_cancelation_requested() );\n}\n\nBOOST_FIXTURE_TEST_CASE( request_cancelationen_when_indication_added, link_layer )\n{\n    const bool result = queue_lcap_notification(\n        bluetoe::details::notification_data( 4, 1 ), this, bluetoe::details::notification_type::indication );\n\n    BOOST_CHECK( result );\n    BOOST_CHECK( event_cancelation_requested() );\n}\n\nBOOST_FIXTURE_TEST_CASE( no_request_when_notification_already_queued, link_layer )\n{\n    const bool result = queue_lcap_notification(\n        bluetoe::details::notification_data( 2, 0 ), this, bluetoe::details::notification_type::notification );\n\n    BOOST_CHECK( result );\n    BOOST_CHECK( event_cancelation_requested() );\n\n    BOOST_CHECK( !queue_lcap_notification(\n        bluetoe::details::notification_data( 2, 0 ), this, bluetoe::details::notification_type::notification ) );\n    BOOST_CHECK( !event_cancelation_requested() );\n}\n\nBOOST_FIXTURE_TEST_CASE( no_request_when_indication_already_queued, link_layer )\n{\n    const bool result = queue_lcap_notification(\n        bluetoe::details::notification_data( 4, 1 ), this, bluetoe::details::notification_type::indication );\n\n    BOOST_CHECK( result );\n    BOOST_CHECK( event_cancelation_requested() );\n\n    BOOST_CHECK( !queue_lcap_notification(\n        bluetoe::details::notification_data( 4, 1 ), this, bluetoe::details::notification_type::indication ) );\n    BOOST_CHECK( !event_cancelation_requested() );\n}\n\nBOOST_FIXTURE_TEST_CASE( no_request_when_confirmation_received, link_layer )\n{\n    const bool result = queue_lcap_notification(\n        bluetoe::details::notification_data( 2, 0 ), this, bluetoe::details::notification_type::confirmation );\n\n    BOOST_CHECK( result );\n    BOOST_CHECK( !event_cancelation_requested() );\n\n}\n\n"
  },
  {
    "path": "tests/link_layer/ll_peripheral_latency_tests.cpp",
    "content": "#define BOOST_TEST_MODULE\n#include <boost/test/included/unit_test.hpp>\n\n#include \"connected.hpp\"\n\nstd::uint16_t temperature_value = 0;\n\n// We test with a relative small hop of 5 for easier calculations\nstatic const std::initializer_list< std::uint8_t > five_hop_connection_request_pdu =\n{\n    0xc5, 0x22,                         // header\n    0x3c, 0x1c, 0x62, 0x92, 0xf0, 0x48, // InitA: 48:f0:92:62:1c:3c (random)\n    0x47, 0x11, 0x08, 0x15, 0x0f, 0xc0, // AdvA:  c0:0f:15:08:11:47 (random)\n    0x5a, 0xb3, 0x9a, 0xaf,             // Access Address\n    0x08, 0x81, 0xf6,                   // CRC Init\n    0x03,                               // transmit window size\n    0x0b, 0x00,                         // window offset\n    0x18, 0x00,                         // interval (30ms)\n    0x03, 0x00,                         // peripheral latency\n    0x48, 0x00,                         // connection timeout (720ms)\n    0xff, 0xff, 0xff, 0xff, 0x1f,       // used channel map\n    0xa5                                // hop increment and sleep clock accuracy (5 and 50ppm)\n};\n\nusing server_t = bluetoe::server<\n    bluetoe::service<\n        bluetoe::service_uuid< 0x8C8B4094, 0x0DE2, 0x499F, 0xA28A, 0x4EED5BC73CA9 >,\n        bluetoe::characteristic<\n            bluetoe::characteristic_uuid< 0x8C8B4094, 0x0DE2, 0x499F, 0xA28A, 0x4EED5BC73CAA >,\n            bluetoe::bind_characteristic_value< decltype( temperature_value ), &temperature_value >,\n            bluetoe::no_write_access,\n            bluetoe::notify\n        >\n    >,\n    bluetoe::no_gap_service_for_gatt_servers\n>;\n\n/*\n * Currently, there is no data to distingusish between Data Available and Unacknowledged Data Available,\n * so lets defere, what to do about that and just test with both options set\n */\nstruct fixture_with_listen_if_pending_transmit_data_option\n    : unconnected_base_t<\n        server_t,\n        test::radio,\n        bluetoe::link_layer::peripheral_latency_configuration<\n            bluetoe::link_layer::peripheral_latency::listen_if_pending_transmit_data,\n            bluetoe::link_layer::peripheral_latency::listen_if_unacknowledged_data\n        >\n    >\n{\n};\n\nBOOST_FIXTURE_TEST_CASE( planned_connection_event_is_rescheduled_when_l2cap_layer_generates_pending_data, fixture_with_listen_if_pending_transmit_data_option )\n{\n    respond_to( 37, five_hop_connection_request_pdu );\n\n    ll_data_pdu( {\n        0x05, 0x00,         // length\n        0x04, 0x00,         // Channel\n        0x12,               // ATT_WRITE_REQ PDU\n        0x04, 0x00,         // CCCD handle\n        0x01, 0x00          // Enable notifications\n    } );\n    ll_empty_pdu();\n    ll_empty_pdu();\n    ll_empty_pdu();\n\n    run();\n\n    BOOST_REQUIRE( connection_events().size() >= 5u );\n\n    // the first connection event happens on channel\n    BOOST_TEST( connection_events()[ 0 ].channel == 5u );\n\n    // the second connection event happens at channel 10, as the respond to the ATT_WRITE_REQ\n    // is available to be send out\n    BOOST_TEST( connection_events()[ 1 ].channel == 10u );\n\n    // the third connection event happens at channel 15, as the outgoing data was not acknowledged\n    BOOST_TEST( connection_events()[ 2 ].channel == 15u );\n\n    // the forth connection event happens at channel 15 + 4 * 5 == 35u, as the next connection\n    // event contains no data\n    BOOST_TEST( connection_events()[ 3 ].channel == 35u );\n}\n\nBOOST_FIXTURE_TEST_CASE( timeout, fixture_with_listen_if_pending_transmit_data_option )\n{\n    respond_to( 37, five_hop_connection_request_pdu );\n\n    // 3 connection events, the first empty, the second, a timeout and the last, empty again\n    ll_empty_pdu();\n    add_connection_event_respond_timeout();\n    ll_empty_pdu();\n\n    run();\n\n    BOOST_REQUIRE( connection_events().size() >= 3u );\n\n    // the first connection event happens on channel 5\n    BOOST_TEST( connection_events()[ 0 ].channel == 5u );\n\n    // the second connection event happens at channel 25 due to the peripheral latency\n    BOOST_TEST( connection_events()[ 1 ].channel == 25u );\n\n    // the third connection event happens at channel 30, due to the timeout\n    BOOST_TEST( connection_events()[ 2 ].channel == 30u );\n}\n\n/*\n * This test makes sure, that the instance at which the next connection parameters\n * become valid will be taken\n */\nBOOST_FIXTURE_TEST_CASE( connection_parameter_update, fixture_with_listen_if_pending_transmit_data_option )\n{\n    respond_to( 37, five_hop_connection_request_pdu );\n    ll_empty_pdu();\n    add_connection_update_request(\n        6, 3, 6,\n        // latency: 66, timeout: 198, instance: 10\n        66, 198, 10 );\n    add_empty_pdus( 3 );\n\n    run();\n\n    // first connection event at channel 5\n\n    BOOST_REQUIRE( connection_events().size() >= 4u );\n\n    // the first connection event happens on channel 5 (instance = 0)\n    BOOST_TEST( connection_events()[ 0 ].channel == 5u );\n\n    // the second connection event happens at channel 25 due to the peripheral latency (instance = 4)\n    BOOST_TEST( connection_events()[ 1 ].channel == 25u );\n\n    // third connection event happens at 25 + 4 * 5 due to peripheral latency (instance = 8)\n    BOOST_TEST( connection_events()[ 2 ].channel == 45u % 37u );\n\n    // 4th connection event happens instance == 10\n    BOOST_TEST( connection_events()[ 3 ].channel == 55u % 37u );\n}\n\nusing config1 = bluetoe::link_layer::peripheral_latency_configuration<>;\nusing config2 = bluetoe::link_layer::peripheral_latency_configuration<\n                    bluetoe::link_layer::peripheral_latency::listen_if_pending_transmit_data,\n                    bluetoe::link_layer::peripheral_latency::listen_if_unacknowledged_data\n                >;\n\nstruct fixture_with_runtime_configuration\n    : unconnected_base_t<\n        server_t,\n        test::radio,\n        bluetoe::link_layer::peripheral_latency_configuration_set< config1, config2 >\n    >\n{\n};\n\nBOOST_FIXTURE_TEST_CASE( change_peripheral_configuration_at_runtime, fixture_with_runtime_configuration )\n{\n    this->respond_to( 37, five_hop_connection_request_pdu );\n\n    ll_data_pdu( {\n        0x05, 0x00,         // length\n        0x04, 0x00,         // Channel\n        0x12,               // ATT_WRITE_REQ PDU\n        0x04, 0x00,         // CCCD handle\n        0x01, 0x00          // Enable notifications\n    } );\n    ll_empty_pdu();\n    ll_function_call( [&](){\n        change_peripheral_latency< config2 >();\n    } );\n    ll_data_pdu( {\n        0x05, 0x00,         // length\n        0x04, 0x00,         // Channel\n        0x12,               // ATT_WRITE_REQ PDU\n        0x04, 0x00,         // CCCD handle\n        0x00, 0x00          // Disable notifications\n    } );\n    ll_empty_pdu();\n\n    this->run();\n\n    // the first connection event happens on channel 5\n    BOOST_TEST( connection_events()[ 0 ].channel == 5u );\n\n    // the second and third connection event happens at channel 25, despide the fact, that\n    // outgoing data is present.\n    BOOST_TEST( connection_events()[ 1 ].channel == 25u );\n    BOOST_TEST( connection_events()[ 2 ].channel == 45u % 37u);\n\n    // Now switching configurations to take next possible connection event, if outgoing data is available\n    BOOST_TEST( connection_events()[ 3 ].channel == 65u % 37u);\n\n    BOOST_TEST( connection_events()[ 4 ].channel == 70u % 37u);\n    BOOST_TEST( connection_events()[ 5 ].channel == 75u % 37u);\n}\n"
  },
  {
    "path": "tests/link_layer/ll_phy_update_tests.cpp",
    "content": "#define BOOST_TEST_MODULE\n#include <boost/test/included/unit_test.hpp>\n\n#include <bluetoe/link_layer.hpp>\n\n#include \"connected.hpp\"\n\nstruct no_2mbit : unconnected_base_t<\n    test::small_temperature_service,\n    test::radio_no_2mbit >\n{\n    no_2mbit()\n    {\n        this->respond_to( 37, valid_connection_request_pdu );\n    }\n};\n\nBOOST_FIXTURE_TEST_SUITE( no_support_by_hardware, no_2mbit )\n\n    using test::X;\n\n    BOOST_AUTO_TEST_CASE( no_phy_update_feature )\n    {\n        ll_control_pdu(\n            {\n                0x08,                    // LL_FEATURE_REQ\n                0x00, 0x00, 0x00, 0x00,\n                0x00, 0x00, 0x00, 0x00\n            } );\n\n        ll_empty_pdu();\n\n        run( 5 );\n\n        check_outgoing_ll_control_pdu(\n            {\n                0x09,                   // LL_FEATURE_RSP\n                X, 0x00, X, X,\n                X, X, X, X\n            }\n        );\n    }\n\n    BOOST_AUTO_TEST_CASE( no_phy_update_feature_feature_mask )\n    {\n        BOOST_CHECK_EQUAL( supported_link_layer_features() & 0x100, 0 );\n    }\n\n    BOOST_AUTO_TEST_CASE( phy_request_not_supported )\n    {\n        ll_control_pdu(\n            {\n                0x16,                       // LL_PHY_REQ\n                0x07,\n                0x07\n            }\n        );\n\n        ll_empty_pdu();\n\n        run( 5 );\n\n        check_outgoing_ll_control_pdu(\n            {\n                0x07,                       // LL_UNKNOWN_RSP\n                0x16                        // LL_PHY_REQ\n            }\n        );\n    }\n\n    BOOST_AUTO_TEST_CASE( phy_update_not_supported )\n    {\n        ll_control_pdu(\n            {\n                0x18,                       // LL_PHY_UPDATE_IND\n                0x01,                       // -> 2Mbit\n                0x01,                       // -> 2Mbit\n                0x10, 0x00\n            }\n        );\n\n        ll_empty_pdu();\n\n        run( 5 );\n\n        check_outgoing_ll_control_pdu(\n            {\n                0x07,                       // LL_UNKNOWN_RSP\n                0x18                        // LL_PHY_UPDATE_IND\n            }\n        );\n    }\n\nBOOST_AUTO_TEST_SUITE_END()\n\nstruct with_2mbit : unconnected_base_t<\n    test::small_temperature_service,\n    test::radio_with_2mbit >\n{\n    with_2mbit()\n    {\n        this->respond_to( 37, valid_connection_request_pdu );\n    }\n};\n\nBOOST_FIXTURE_TEST_SUITE( support_by_hardware, with_2mbit )\n\n    using test::X;\n\n    BOOST_AUTO_TEST_CASE( phy_update_feature )\n    {\n        ll_control_pdu(\n            {\n                0x08,                    // LL_FEATURE_REQ\n                0x00, 0x00, 0x00, 0x00,\n                0x00, 0x00, 0x00, 0x00\n            } );\n\n        ll_empty_pdu();\n\n        run( 5 );\n\n        check_outgoing_ll_control_pdu(\n            {\n                0x09,                   // LL_FEATURE_RSP\n                X, 0x01, X, X,\n                X, X, X, X\n            }\n        );\n    }\n\n    BOOST_AUTO_TEST_CASE( phy_update_feature_feature_mask )\n    {\n        BOOST_CHECK_EQUAL( supported_link_layer_features() & 0x100, 0x100 );\n    }\n\n    BOOST_AUTO_TEST_CASE( phy_response )\n    {\n        ll_control_pdu(\n            {\n                0x16,                       // LL_PHY_REQ\n                0x07,\n                0x07\n            }\n        );\n\n        ll_empty_pdu();\n\n        run( 5 );\n\n        check_outgoing_ll_control_pdu(\n            {\n                0x17,                       // LL_PHY_RSP\n                0x03,                       // Sender prefers to use the LE 1M PHY (possibly among others)\n                                            // Sender prefers to use the LE 2M PHY (possibly among others)\n                0x03,                       // Sender prefers to use the LE 1M PHY (possibly among others)\n                                            // Sender prefers to use the LE 2M PHY (possibly among others)\n            }\n        );\n    }\n\n    BOOST_AUTO_TEST_CASE( phy_request_wrong_size )\n    {\n        ll_control_pdu(\n            {\n                0x16,                       // LL_PHY_REQ\n                0x07\n            }\n        );\n\n        ll_empty_pdu();\n\n        run( 5 );\n\n        check_outgoing_ll_control_pdu(\n            {\n                0x07,                       // LL_UNKNOWN_RSP\n                0x16                        // LL_PHY_REQ\n            }\n        );\n    }\n\n    BOOST_AUTO_TEST_CASE( phy_update )\n    {\n        ll_control_pdu(\n            {\n                0x18,                       // LL_PHY_UPDATE_IND\n                0x01,                       // Central -> Peripheral: 1MBit\n                0x02,                       // Peripheral -> Central: 2MBit\n                0x07, 0x00                  // Instance: 0x0007\n            }\n        );\n\n        ll_empty_pdu();\n        ll_empty_pdu();\n        ll_empty_pdu();\n        ll_empty_pdu();\n        ll_empty_pdu();\n        ll_empty_pdu();\n        ll_empty_pdu();\n\n        run( 8 );\n\n        BOOST_CHECK_EQUAL( connection_events()[ 6 ].receiving_encoding   , bluetoe::link_layer::phy_ll_encoding::le_1m_phy );\n        BOOST_CHECK_EQUAL( connection_events()[ 6 ].transmission_encoding, bluetoe::link_layer::phy_ll_encoding::le_1m_phy );\n\n        BOOST_CHECK_EQUAL( connection_events()[ 7 ].receiving_encoding   , bluetoe::link_layer::phy_ll_encoding::le_1m_phy );\n        BOOST_CHECK_EQUAL( connection_events()[ 7 ].transmission_encoding, bluetoe::link_layer::phy_ll_encoding::le_2m_phy );\n    }\n\n    BOOST_AUTO_TEST_CASE( phy_update_no_update )\n    {\n        ll_control_pdu(\n            {\n                0x18,                       // LL_PHY_UPDATE_IND\n                0x00,                       // Central -> Peripheral: no update\n                0x00,                       // Peripheral -> Central: no update\n                0x07, 0x00                  // Instance: 0x0007\n            }\n        );\n\n        ll_empty_pdu();\n        ll_empty_pdu();\n        ll_empty_pdu();\n        ll_empty_pdu();\n        ll_empty_pdu();\n        ll_empty_pdu();\n        ll_empty_pdu();\n\n        run( 8 );\n\n        BOOST_CHECK_EQUAL( connection_events()[ 6 ].receiving_encoding   , bluetoe::link_layer::phy_ll_encoding::le_1m_phy );\n        BOOST_CHECK_EQUAL( connection_events()[ 6 ].transmission_encoding, bluetoe::link_layer::phy_ll_encoding::le_1m_phy );\n\n        BOOST_CHECK_EQUAL( connection_events()[ 7 ].receiving_encoding   , bluetoe::link_layer::phy_ll_encoding::le_1m_phy );\n        BOOST_CHECK_EQUAL( connection_events()[ 7 ].transmission_encoding, bluetoe::link_layer::phy_ll_encoding::le_1m_phy );\n    }\n\n    BOOST_AUTO_TEST_CASE( phy_p_to_c_update )\n    {\n        ll_control_pdu(\n            {\n                0x18,                       // LL_PHY_UPDATE_IND\n                0x00,                       // Central -> Peripheral: no update\n                0x02,                       // Peripheral -> Central: 2 MBit\n                0x07, 0x00                  // Instance: 0x0007\n            }\n        );\n\n        ll_empty_pdu();\n        ll_empty_pdu();\n        ll_empty_pdu();\n        ll_empty_pdu();\n        ll_empty_pdu();\n        ll_empty_pdu();\n        ll_empty_pdu();\n\n        run( 8 );\n\n        BOOST_CHECK_EQUAL( connection_events()[ 6 ].receiving_encoding   , bluetoe::link_layer::phy_ll_encoding::le_1m_phy );\n        BOOST_CHECK_EQUAL( connection_events()[ 6 ].transmission_encoding, bluetoe::link_layer::phy_ll_encoding::le_1m_phy );\n\n        BOOST_CHECK_EQUAL( connection_events()[ 7 ].receiving_encoding   , bluetoe::link_layer::phy_ll_encoding::le_1m_phy );\n        BOOST_CHECK_EQUAL( connection_events()[ 7 ].transmission_encoding, bluetoe::link_layer::phy_ll_encoding::le_2m_phy );\n    }\n\n    BOOST_AUTO_TEST_CASE( phy_update_wrong_size )\n    {\n        ll_control_pdu(\n            {\n                0x18,                       // LL_PHY_UPDATE_IND\n                0x01,                       // Central -> Peripheral: 1MBit\n                0x02,                       // Peripheral -> Central: 2MBit\n                0x07, 0x00,                 // Instance: 0x0007\n                0xFF                        // Additional, not expected\n            }\n        );\n\n        ll_empty_pdu();\n\n        run( 5 );\n\n        check_outgoing_ll_control_pdu(\n            {\n                0x07,                       // LL_UNKNOWN_RSP\n                0x18                        // LL_PHY_UPDATE_IND\n            }\n        );\n    }\n\n    BOOST_AUTO_TEST_CASE( phy_update_multiple_c_to_p_bits )\n    {\n        ll_control_pdu(\n            {\n                0x18,                       // LL_PHY_UPDATE_IND\n                0x03,                       // Central -> Peripheral: 1MBit + 2MBit\n                0x00,                       // Peripheral -> Central: no change\n                0x07, 0x00                  // Instance: 0x0007\n            }\n        );\n\n        ll_empty_pdu();\n\n        run( 5 );\n\n        check_outgoing_ll_control_pdu(\n            {\n                0x07,                       // LL_UNKNOWN_RSP\n                0x18                        // LL_PHY_UPDATE_IND\n            }\n        );\n    }\n\n    BOOST_AUTO_TEST_CASE( phy_update_multiple_p_to_c_bits )\n    {\n        ll_control_pdu(\n            {\n                0x18,                       // LL_PHY_UPDATE_IND\n                0x00,                       // Central -> Peripheral: no change\n                0x03,                       // Peripheral -> Central: 1MBit + 2MBit\n                0x07, 0x00                  // Instance: 0x0007\n            }\n        );\n\n        ll_empty_pdu();\n\n        run( 5 );\n\n        check_outgoing_ll_control_pdu(\n            {\n                0x07,                       // LL_UNKNOWN_RSP\n                0x18                        // LL_PHY_UPDATE_IND\n            }\n        );\n    }\n\nBOOST_AUTO_TEST_SUITE_END()\n\nstruct with_2mbit_and_latency : unconnected_base_t<\n    test::small_temperature_service,\n    test::radio_with_2mbit >\n{\n    with_2mbit_and_latency()\n    {\n        this->respond_to( 37, {\n            0xc5, 0x22,                         // header\n            0x3c, 0x1c, 0x62, 0x92, 0xf0, 0x48, // InitA: 48:f0:92:62:1c:3c (random)\n            0x47, 0x11, 0x08, 0x15, 0x0f, 0xc0, // AdvA:  c0:0f:15:08:11:47 (random)\n            0x5a, 0xb3, 0x9a, 0xaf,             // Access Address\n            0x08, 0x81, 0xf6,                   // CRC Init\n            0x03,                               // transmit window size\n            0x0b, 0x00,                         // window offset\n            0x18, 0x00,                         // interval (30ms)\n            0x0A, 0x00,                         // peripheral latency\n            0x48, 0x00,                         // connection timeout (720ms)\n            0xff, 0xff, 0xff, 0xff, 0x1f,       // used channel map\n            0xaa                                // hop increment and sleep clock accuracy (10 and 50ppm)\n        } );\n    }\n};\n\nBOOST_FIXTURE_TEST_SUITE( with_peripheral_latency, with_2mbit_and_latency )\n\n    BOOST_AUTO_TEST_CASE( phy_p_to_c_update )\n    {\n        ll_control_pdu(\n            {\n                0x18,                       // LL_PHY_UPDATE_IND\n                0x02,                       // Central -> Peripheral: 2 MBit\n                0x02,                       // Peripheral -> Central: 2 MBit\n                0x07, 0x00                  // Instance: 0x0007\n            }\n        );\n\n        ll_empty_pdu();\n        ll_empty_pdu();\n\n        run( 3 );\n\n        BOOST_CHECK_EQUAL( connection_events()[ 0 ].receiving_encoding   , bluetoe::link_layer::phy_ll_encoding::le_1m_phy );\n        BOOST_CHECK_EQUAL( connection_events()[ 0 ].transmission_encoding, bluetoe::link_layer::phy_ll_encoding::le_1m_phy );\n\n        BOOST_CHECK_EQUAL( connection_events()[ 1 ].receiving_encoding   , bluetoe::link_layer::phy_ll_encoding::le_2m_phy );\n        BOOST_CHECK_EQUAL( connection_events()[ 1 ].transmission_encoding, bluetoe::link_layer::phy_ll_encoding::le_2m_phy );\n    }\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "tests/link_layer/ll_remote_request_tests.cpp",
    "content": "#define BOOST_TEST_MODULE\n#include <boost/test/included/unit_test.hpp>\n\n#include \"connected.hpp\"\n\nstruct callbacks_t\n{\n    callbacks_t()\n        : connection_closed( false )\n        , version_received( false )\n        , connection_changed( false )\n    {\n    }\n\n    template < class ConnectionData >\n    void ll_connection_closed( std::uint8_t reason, ConnectionData& )\n    {\n        connection_closed = true;\n        closed_reason = reason;\n    }\n\n    template < class ConnectionData >\n    void ll_version( std::uint8_t version, std::uint16_t company, std::uint16_t subversion, const ConnectionData& )\n    {\n        version_received = true;\n        version_version  = version;\n        version_company  = company;\n        version_subversion = subversion;\n    }\n\n    template < typename ConnectionData >\n    void ll_connection_changed(\n        const bluetoe::link_layer::connection_details& details, ConnectionData& )\n    {\n        connection_changed = true;\n        changed_details    = details;\n    }\n\n    bool            connection_closed;\n    std::uint8_t    closed_reason;\n\n    bool            version_received;\n    std::uint8_t    version_version;\n    std::uint16_t   version_company;\n    std::uint16_t   version_subversion;\n\n    bool            connection_changed;\n    bluetoe::link_layer::connection_details changed_details;\n\n} callbacks;\n\nstruct fixture : unconnected_base<\n    bluetoe::link_layer::connection_callbacks< callbacks_t, callbacks > >\n{\n    fixture()\n    {\n        callbacks = callbacks_t();\n        this->respond_to( 37, valid_connection_request_pdu );\n    }\n};\n\nusing test::X;\n\nBOOST_FIXTURE_TEST_CASE( request_to_2mbit, fixture )\n{\n    ll_empty_pdus( 1 );\n    ll_function_call( [this](){\n        BOOST_CHECK( phy_update_request_to_2mbit() );\n        BOOST_CHECK( !phy_update_request_to_2mbit() );\n    });\n    ll_empty_pdus( 4 );\n\n    run( 5 );\n\n    check_outgoing_ll_control_pdu(\n        {\n            0x16,                   // LL_PHY_REQ\n            0x02,                   // LE 2M PHY\n            0x02                    // LE 2M PHY\n        }\n    );\n}\n\nBOOST_FIXTURE_TEST_CASE( request_to_1_2mbit, fixture )\n{\n    ll_empty_pdus( 1 );\n    ll_function_call( [this](){\n        BOOST_CHECK(\n            phy_update_request(\n                bluetoe::link_layer::phy_ll_encoding::le_1m_phy,\n                bluetoe::link_layer::phy_ll_encoding::le_2m_phy ) );\n    });\n    ll_empty_pdus( 4 );\n\n    run( 5 );\n\n    check_outgoing_ll_control_pdu(\n        {\n            0x16,                   // LL_PHY_REQ\n            0x01,                   // LE 1M PHY\n            0x02                    // LE 2M PHY\n        }\n    );\n}\n\nBOOST_FIXTURE_TEST_CASE( request_to_2_xmbit, fixture )\n{\n    ll_empty_pdus( 1 );\n    ll_function_call( [this](){\n        BOOST_CHECK(\n            phy_update_request(\n                bluetoe::link_layer::phy_ll_encoding::le_2m_phy,\n                bluetoe::link_layer::phy_ll_encoding::le_unchanged_coding ) );\n    });\n    ll_empty_pdus( 4 );\n\n    run( 5 );\n\n    check_outgoing_ll_control_pdu(\n        {\n            0x16,                   // LL_PHY_REQ\n            0x02,                   // LE 2M PHY\n            0x00                    // unchanged\n        }\n    );\n}\n\nBOOST_FIXTURE_TEST_CASE( request_to_remote_version, fixture )\n{\n    ll_empty_pdus( 1 );\n    ll_function_call( [this](){\n        BOOST_CHECK( remote_versions_request() );\n        BOOST_CHECK( !remote_versions_request() );\n    });\n    ll_empty_pdus( 4 );\n\n    run( 5 );\n\n    check_outgoing_ll_control_pdu(\n        {\n            0x0C,                   // LL_VERSION_IND\n            0x09,                   // Version\n            0x69, 0x02,             // Company_Identifier\n            0x00, 0x00              // Subversion\n        }\n    );\n}\n\nBOOST_FIXTURE_TEST_CASE( request_to_remote_version_pending_till_response, fixture )\n{\n    ll_empty_pdus( 1 );\n    ll_function_call( [this](){\n        BOOST_CHECK( remote_versions_request() );\n        BOOST_CHECK( !remote_versions_request() );\n    });\n    ll_empty_pdus( 4 );\n    ll_function_call( [this](){\n        // even after sending out the LL_VERSION_IND PDU, any procedure\n        // is looked due to the still pending procedure. Procedure\n        // is still pending, as no response was received yet.\n        BOOST_CHECK( !remote_versions_request() );\n    });\n    ll_control_pdu(\n        {\n            0x0C,                   // LL_VERSION_IND\n            0x08,                   // Version\n            0x47, 0x11,             // Company_Identifier\n            0x08, 0x15              // Subversion\n        }\n    );\n\n    run( 5 );\n\n    check_outgoing_ll_control_pdu(\n        {\n            0x0C,                   // LL_VERSION_IND\n            0x09,                   // Version\n            0x69, 0x02,             // Company_Identifier\n            0x00, 0x00              // Subversion\n        }\n    );\n\n    // Now again, we can request the remote version\n    ll_function_call( [this](){\n        BOOST_CHECK( remote_versions_request() );\n    });\n    ll_empty_pdus( 4 );\n\n    run( 5 );\n\n    check_outgoing_ll_control_pdu(\n        {\n            0x0C,                   // LL_VERSION_IND\n            0x09,                   // Version\n            0x69, 0x02,             // Company_Identifier\n            0x00, 0x00              // Subversion\n        }\n    );\n}\n\n/**\n * \"If the procedure response timeout timer reaches 40 seconds, the ACL connection\n * is considered lost (see Section 4.5.12). The Link Layer exits the Connection\n * state and shall transition to the Standby state. The Host shall be notified of\n * the loss of connection.\"\n *\n * LL/CON/PER/BI-05-C\n */\nBOOST_FIXTURE_TEST_CASE( request_to_remote_version_timeout, fixture )\n{\n    ll_empty_pdus( 1 );\n    ll_function_call( [this](){\n        BOOST_CHECK( remote_versions_request() );\n    });\n    // connection interval is 30ms / timeout 4000ms = 1333,3\n    ll_empty_pdus( 1330 );\n    ll_function_call( [this](){\n        BOOST_CHECK( !callbacks.connection_closed );\n        BOOST_CHECK( !remote_versions_request() );\n    });\n    ll_empty_pdus( 3 );\n    ll_function_call( [](){\n        BOOST_CHECK( callbacks.connection_closed );\n    });\n\n    run( 1500 );\n\n    BOOST_CHECK( callbacks.connection_closed );\n    BOOST_CHECK_EQUAL( callbacks.closed_reason, 0x22 );\n}\n\n/**\n * LL/CON/PER/BV-24-C\n */\nBOOST_FIXTURE_TEST_CASE( Initiating_Connection_Parameter_Request__Accept, fixture )\n{\n    ll_empty_pdus( 1 );\n    ll_function_call( [this](){\n        BOOST_CHECK( initiating_connection_parameter_request( 6, 6, 0, 300 ) );\n        BOOST_CHECK( !initiating_connection_parameter_request( 6, 6, 0, 300 ) );\n    });\n    ll_empty_pdus( 4 );\n\n    ll_control_pdu(\n        {\n            0x00,                   // LL_CONNECTION_UPDATE_IND\n            0x01,                   // WinSize\n            0x06, 0x00,             // WinOffset\n            0x06, 0x00,             // Interval\n            0x00, 0x00,             // Latency\n            0x2c, 0x01,             // Timeout\n            0x0A, 0x00              // Instant\n        }\n    );\n    ll_empty_pdus( 20 );\n\n    run( 25 );\n\n    check_outgoing_ll_control_pdu(\n        {\n            0x0F,                   // LL_CONNECTION_PARAM_REQ\n            0x06, 0x00,             // Interval_Min\n            0x06, 0x00,             // Interval_Max\n            0x00, 0x00,             // Latency\n            0x2c, 0x01,             // Timeout\n            0x00,                   // PreferredPeriodicity\n            0x00, 0x00,             // ReferenceConnEventCount\n            0xff, 0xff,             // Offset0\n            0xff, 0xff,             // Offset1\n            0xff, 0xff,             // Offset2\n            0xff, 0xff,             // Offset3\n            0xff, 0xff,             // Offset4\n            0xff, 0xff,             // Offset5\n        }\n    );\n\n    BOOST_CHECK( callbacks.connection_changed );\n    BOOST_CHECK_EQUAL( callbacks.changed_details.interval(), 0x0006 );\n    BOOST_CHECK_EQUAL( callbacks.changed_details.latency(), 0x0000 );\n    BOOST_CHECK_EQUAL( callbacks.changed_details.timeout(), 0x012c );\n\n    // Finally, a new update request will be accepted again\n    BOOST_CHECK( initiating_connection_parameter_request( 6, 7, 1, 300 ) );\n}\n\n/**\n * LL/CON/PER/BI-07-C\n */\nBOOST_FIXTURE_TEST_CASE( Initiating_Connection_Parameter_Request__Timeout, fixture )\n{\n    ll_empty_pdus( 1 );\n    ll_function_call( [this](){\n        BOOST_CHECK( initiating_connection_parameter_request( 6, 6, 0, 300 ) );\n    });\n    // connection interval is 30ms / timeout 4000ms = 1333,3\n    ll_empty_pdus( 1330 );\n    ll_function_call( [this](){\n        BOOST_CHECK( !callbacks.connection_closed );\n        BOOST_CHECK( !initiating_connection_parameter_request( 6, 6, 0, 300 ) );\n    });\n    ll_empty_pdus( 3 );\n    ll_function_call( [](){\n        BOOST_CHECK( callbacks.connection_closed );\n    });\n\n    run( 1500 );\n\n    BOOST_CHECK( callbacks.connection_closed );\n    BOOST_CHECK_EQUAL( callbacks.closed_reason, 0x22 );\n}\n\nBOOST_FIXTURE_TEST_CASE( Initiating_Connection_Parameter_Request__Reject_No_Timeout, fixture )\n{\n    bool tested = false;\n\n    ll_empty_pdus( 1 );\n    ll_function_call( [this](){\n        BOOST_CHECK( initiating_connection_parameter_request( 6, 6, 0, 300 ) );\n        BOOST_CHECK( !initiating_connection_parameter_request( 6, 6, 0, 300 ) );\n    });\n    ll_empty_pdus( 4 );\n\n    ll_control_pdu(\n        {\n            0x11,                   // LL_REJECT_EXT_IND\n            0x0F,                   // LL_CONNECTION_PARAM_REQ\n            0x06                    // Error Code\n        }\n    );\n\n    // connection interval is 30ms / timeout 4000ms = 1333,3\n    ll_empty_pdus( 1340 );\n    ll_function_call( [&](){\n        tested = true;\n        BOOST_CHECK( !callbacks.connection_closed );\n    });\n    ll_empty_pdus( 3 );\n\n    run(1500);\n\n    // make sure, the important test above is part of the simulation\n    BOOST_CHECK( tested );\n}\n"
  },
  {
    "path": "tests/link_layer/peripheral_latency_tests.cpp",
    "content": "#define BOOST_TEST_MODULE\n#include <boost/test/included/unit_test.hpp>\n\n#include <bluetoe/link_layer.hpp>\n\nstruct no_peripheral_latency : bluetoe::link_layer::details::peripheral_latency_state<\n    bluetoe::link_layer::peripheral_latency_ignored\n>\n{\n    no_peripheral_latency()\n    {\n        reset_connection_state();\n    }\n};\n\nstatic const bluetoe::link_layer::delta_time typical_connection_interval =\n    bluetoe::link_layer::delta_time::msec( 30 );\n\nstatic const bluetoe::link_layer::delta_time half_typical_connection_interval =\n    bluetoe::link_layer::delta_time::msec( 15 );\n\nstatic const bluetoe::link_layer::connection_event_events no_events;\nstatic const bluetoe::link_layer::connection_event_events all_events = { true, true, true, true, true, true };\nstatic const bluetoe::link_layer::connection_event_events all_but_error_events = { true, true, true, true, true, false };\nstatic const bluetoe::link_layer::connection_event_events unacknowledged_data_events = { true, false, false, false, false, false };\nstatic const bluetoe::link_layer::connection_event_events last_received_not_empty_events = { false, true, false, false, false, false };\nstatic const bluetoe::link_layer::connection_event_events last_transmitted_not_empty_events = { false, false, true, false, false, false };\nstatic const bluetoe::link_layer::connection_event_events last_received_had_more_data_events = { false, false, false, true, false, false };\nstatic const bluetoe::link_layer::connection_event_events pending_outgoing_data_events = { false, false, false, false, true, false };\nstatic const bluetoe::link_layer::connection_event_events last_error_events = { false, false, false, false, false, true };\n\nstatic const std::pair< bool, std::int16_t > no_pending_instance = { false, 0u };\n\nBOOST_FIXTURE_TEST_SUITE( no_peripheral_latency_applied, no_peripheral_latency )\n\n    BOOST_AUTO_TEST_CASE( initial_state )\n    {\n        BOOST_TEST( current_channel_index() == 0u );\n        BOOST_TEST( connection_event_counter() == 0u );\n        BOOST_TEST( time_since_last_event().zero() );\n    }\n\n    BOOST_AUTO_TEST_CASE( channel_index_is_incremented_by_one )\n    {\n        // without peripheral latency\n        plan_next_connection_event(\n            0, no_events, typical_connection_interval, no_pending_instance );\n\n        BOOST_TEST( current_channel_index() == 1u );\n\n        // with peripheral latency\n        plan_next_connection_event(\n            10, no_events, typical_connection_interval, no_pending_instance );\n\n        BOOST_TEST( current_channel_index() == 2u );\n\n        // when a timeout happens, without peripheral latency\n        plan_next_connection_event_after_timeout(\n            typical_connection_interval );\n\n        BOOST_TEST( current_channel_index() == 3u );\n\n        // when a timeout happens, without peripheral latency\n        plan_next_connection_event_after_timeout(\n            typical_connection_interval );\n\n        BOOST_TEST( current_channel_index() == 4u );\n\n        // with peripheral latency and all sort of events\n        plan_next_connection_event(\n            10, all_events, typical_connection_interval, no_pending_instance );\n\n        BOOST_TEST( current_channel_index() == 5u );\n    }\n\n    BOOST_AUTO_TEST_CASE( event_counter_increments_by_one )\n    {\n        // without peripheral latency\n        plan_next_connection_event(\n            0, no_events, typical_connection_interval, no_pending_instance );\n\n        BOOST_TEST( connection_event_counter() == 1u );\n\n        // with peripheral latency\n        plan_next_connection_event(\n            10, no_events, typical_connection_interval, no_pending_instance );\n\n        BOOST_TEST( connection_event_counter() == 2u );\n\n        // when a timeout happens, without peripheral latency\n        plan_next_connection_event_after_timeout(\n            typical_connection_interval );\n\n        BOOST_TEST( connection_event_counter() == 3u );\n\n        // when a timeout happens, without peripheral latency\n        plan_next_connection_event_after_timeout(\n            typical_connection_interval );\n\n        BOOST_TEST( connection_event_counter() == 4u );\n    }\n\n    BOOST_AUTO_TEST_CASE( channel_index_wraps_after_36 )\n    {\n        for ( int i = 0; i != 36; ++i )\n        {\n            plan_next_connection_event(\n                0, no_events, typical_connection_interval, no_pending_instance );\n        }\n\n        BOOST_TEST( current_channel_index() == 36u );\n\n        plan_next_connection_event(\n            0, no_events, typical_connection_interval, no_pending_instance );\n\n        BOOST_TEST( current_channel_index() == 0u );\n    }\n\n    BOOST_AUTO_TEST_CASE( instance_counter_wraps_after_ffff )\n    {\n        for ( int i = 0; i != 0xffff; ++i )\n        {\n            plan_next_connection_event(\n                0, no_events, typical_connection_interval, no_pending_instance );\n        }\n\n        BOOST_TEST( connection_event_counter() == 0xffffu );\n\n        plan_next_connection_event(\n            0, no_events, typical_connection_interval, no_pending_instance );\n\n        BOOST_TEST( connection_event_counter() == 0u );\n    }\n\n    BOOST_AUTO_TEST_CASE( time_since_last_event_is_set_to_interval )\n    {\n        plan_next_connection_event(\n            0, no_events, typical_connection_interval, no_pending_instance );\n\n        BOOST_TEST( time_since_last_event() == typical_connection_interval );\n\n        plan_next_connection_event(\n            0, no_events, typical_connection_interval, no_pending_instance );\n\n        BOOST_TEST( time_since_last_event() == typical_connection_interval );\n    }\n\n    BOOST_AUTO_TEST_CASE( time_since_last_event_is_cummulated_after_timeout )\n    {\n        plan_next_connection_event_after_timeout(\n            typical_connection_interval );\n\n        BOOST_TEST( time_since_last_event() == typical_connection_interval );\n\n        plan_next_connection_event_after_timeout(\n            typical_connection_interval );\n\n        BOOST_TEST( time_since_last_event() == 2 * typical_connection_interval );\n\n        plan_next_connection_event_after_timeout(\n            2 * typical_connection_interval );\n\n        BOOST_TEST( time_since_last_event() == 4 * typical_connection_interval );\n\n        // and reset after a connection event toke place\n        plan_next_connection_event(\n            0, no_events, typical_connection_interval, no_pending_instance );\n\n        BOOST_TEST( time_since_last_event() == typical_connection_interval );\n    }\n\n    BOOST_AUTO_TEST_CASE( no_disarm_connection_event_support_required )\n    {\n        BOOST_TEST( reschedule_on_pending_data( *this, typical_connection_interval ) == false );\n    }\n\nBOOST_AUTO_TEST_SUITE_END()\n\n// In contrast to ignored latency, a latency that really schedules events only at latency anchors\nstruct peripheral_latency_only_at_anchors : bluetoe::link_layer::details::peripheral_latency_state<\n    bluetoe::link_layer::peripheral_latency_configuration<>\n>\n{\n    peripheral_latency_only_at_anchors()\n    {\n        reset_connection_state();\n    }\n};\n\nBOOST_FIXTURE_TEST_SUITE( only_peripheral_latency_applied, peripheral_latency_only_at_anchors )\n\n    static const int latency = 5;\n\n    BOOST_AUTO_TEST_CASE( initial_state )\n    {\n        BOOST_TEST( current_channel_index() == 0u );\n        BOOST_TEST( connection_event_counter() == 0u );\n        BOOST_TEST( time_since_last_event().zero() );\n    }\n\n    BOOST_AUTO_TEST_CASE( next_connection_events )\n    {\n        plan_next_connection_event(\n            latency, all_but_error_events, typical_connection_interval, no_pending_instance );\n\n        BOOST_TEST( current_channel_index() == 6u );\n        BOOST_TEST( connection_event_counter() == 6u );\n        BOOST_TEST( time_since_last_event() == 6 * typical_connection_interval );\n\n        plan_next_connection_event(\n            latency, all_but_error_events, typical_connection_interval, no_pending_instance );\n\n        BOOST_TEST( current_channel_index() == 12u );\n        BOOST_TEST( connection_event_counter() == 12u );\n        BOOST_TEST( time_since_last_event() == 6 * typical_connection_interval );\n\n        plan_next_connection_event_after_timeout(\n            typical_connection_interval );\n\n        BOOST_TEST( current_channel_index() == 13u );\n        BOOST_TEST( connection_event_counter() == 13u );\n        BOOST_TEST( time_since_last_event() == 7 * typical_connection_interval );\n    }\n\n    BOOST_AUTO_TEST_CASE( channel_index_wraps_after_36 )\n    {\n        for ( int i = 0; i != 6; ++i )\n        {\n            plan_next_connection_event(\n                latency, all_but_error_events, typical_connection_interval, no_pending_instance );\n        }\n\n        BOOST_TEST( current_channel_index() == 36u );\n\n        plan_next_connection_event(\n            0, no_events, typical_connection_interval, no_pending_instance );\n\n        BOOST_TEST( current_channel_index() == 0u );\n    }\n\n    BOOST_AUTO_TEST_CASE( channel_index_wraps_after_36_II )\n    {\n        for ( int i = 0; i != 5; ++i )\n        {\n            plan_next_connection_event(\n                7, all_but_error_events, typical_connection_interval, no_pending_instance );\n        }\n\n        BOOST_TEST( current_channel_index() == 3u );\n\n        plan_next_connection_event(\n            7, no_events, typical_connection_interval, no_pending_instance );\n\n        BOOST_TEST( current_channel_index() == 11u );\n    }\n\n    BOOST_AUTO_TEST_CASE( very_large_latency )\n    {\n        plan_next_connection_event(\n            500, all_but_error_events, typical_connection_interval, no_pending_instance );\n\n        BOOST_TEST( current_channel_index() == 501u % 37);\n        BOOST_TEST( connection_event_counter() == 501u );\n        BOOST_TEST( time_since_last_event() == 501 * typical_connection_interval );\n    }\n\n    BOOST_AUTO_TEST_CASE( no_disarm_connection_event_support_required )\n    {\n        BOOST_TEST( reschedule_on_pending_data( *this, typical_connection_interval ) == false );\n    }\n\n    BOOST_AUTO_TEST_CASE( take_next_event_on_error )\n    {\n        plan_next_connection_event(\n            500, last_error_events, typical_connection_interval, no_pending_instance );\n\n        BOOST_TEST( current_channel_index() == 1u );\n        BOOST_TEST( connection_event_counter() == 1u );\n        BOOST_TEST( time_since_last_event() == 1 * typical_connection_interval );\n    }\n\n    BOOST_AUTO_TEST_CASE( latency_limited_by_pending_instance )\n    {\n        plan_next_connection_event(\n            500, no_events, typical_connection_interval, { true, 299u } );\n\n        BOOST_TEST( current_channel_index() == 299u % 37 );\n        BOOST_TEST( connection_event_counter() == 299u );\n        BOOST_TEST( time_since_last_event() == 299u * typical_connection_interval );\n    }\n\n    BOOST_AUTO_TEST_CASE( latency_not_limited_by_pending_instance )\n    {\n        plan_next_connection_event(\n            100, no_events, typical_connection_interval, { true, 299u } );\n\n        BOOST_TEST( current_channel_index() == 101u % 37 );\n        BOOST_TEST( connection_event_counter() == 101u );\n        BOOST_TEST( time_since_last_event() == 101u * typical_connection_interval );\n    }\n\n    BOOST_AUTO_TEST_CASE( latency_limited_by_pending_instance_after_counter_wrap )\n    {\n        for ( int i = 0; i != 130; ++i )\n            plan_next_connection_event(\n                500, no_events, typical_connection_interval, no_pending_instance );\n\n        BOOST_TEST( current_channel_index() == 65130u % 37 );\n        BOOST_TEST( connection_event_counter() == 65130u );\n        BOOST_TEST( time_since_last_event() == 501u * typical_connection_interval );\n\n        plan_next_connection_event(\n            500, no_events, typical_connection_interval, { true, 20 } );\n\n        BOOST_TEST( current_channel_index() == ( 0x10000 + 20u ) % 37 );\n        BOOST_TEST( connection_event_counter() == 20u );\n        BOOST_TEST( time_since_last_event() == ( 0x10000 - 65130u + 20u ) * typical_connection_interval );\n    }\n\nBOOST_AUTO_TEST_SUITE_END()\n\nstruct listen_if_unacknowledged_data : bluetoe::link_layer::details::peripheral_latency_state<\n    bluetoe::link_layer::peripheral_latency_configuration<\n        bluetoe::link_layer::peripheral_latency::listen_if_unacknowledged_data\n    >\n>\n{\n    listen_if_unacknowledged_data()\n    {\n        reset_connection_state();\n    }\n};\n\nBOOST_FIXTURE_TEST_SUITE( unacknowlaged_data, listen_if_unacknowledged_data )\n\n    static const int latency = 3;\n\n    BOOST_AUTO_TEST_CASE( initial_state )\n    {\n        BOOST_TEST( current_channel_index() == 0u );\n        BOOST_TEST( connection_event_counter() == 0u );\n        BOOST_TEST( time_since_last_event().zero() );\n    }\n\n    BOOST_AUTO_TEST_CASE( following_latency_when_no_event_happend )\n    {\n        plan_next_connection_event(\n            latency, no_events, typical_connection_interval, no_pending_instance );\n\n        BOOST_TEST( current_channel_index() == 4u );\n        BOOST_TEST( connection_event_counter() == 4u );\n        BOOST_TEST( time_since_last_event() == 4 * typical_connection_interval );\n    }\n\n    BOOST_AUTO_TEST_CASE( take_next_event_if_unacknowlaged_data_was_send )\n    {\n        plan_next_connection_event(\n            latency, unacknowledged_data_events, typical_connection_interval, no_pending_instance );\n\n        BOOST_TEST( current_channel_index() == 1u );\n        BOOST_TEST( connection_event_counter() == 1u );\n        BOOST_TEST( time_since_last_event() == 1 * typical_connection_interval );\n\n        plan_next_connection_event(\n            latency, no_events, typical_connection_interval, no_pending_instance );\n\n        BOOST_TEST( current_channel_index() == 5u );\n        BOOST_TEST( connection_event_counter() == 5u );\n        BOOST_TEST( time_since_last_event() == 4 * typical_connection_interval );\n\n        plan_next_connection_event_after_timeout(\n            typical_connection_interval );\n\n        BOOST_TEST( current_channel_index() == 6u );\n        BOOST_TEST( connection_event_counter() == 6u );\n        BOOST_TEST( time_since_last_event() == 5 * typical_connection_interval );\n\n        plan_next_connection_event(\n            latency, unacknowledged_data_events, typical_connection_interval, no_pending_instance );\n\n        BOOST_TEST( current_channel_index() == 7u );\n        BOOST_TEST( connection_event_counter() == 7u );\n        BOOST_TEST( time_since_last_event() == 1 * typical_connection_interval );\n    }\n\n    BOOST_AUTO_TEST_CASE( no_disarm_connection_event_support_required )\n    {\n        BOOST_TEST( reschedule_on_pending_data( *this, typical_connection_interval ) == false );\n    }\n\n    BOOST_AUTO_TEST_CASE( take_next_event_on_error )\n    {\n        plan_next_connection_event(\n            500, last_error_events, typical_connection_interval, no_pending_instance );\n\n        BOOST_TEST( current_channel_index() == 1u );\n        BOOST_TEST( connection_event_counter() == 1u );\n        BOOST_TEST( time_since_last_event() == 1 * typical_connection_interval );\n    }\n\nBOOST_AUTO_TEST_SUITE_END()\n\nstruct listen_if_last_received_not_empty : bluetoe::link_layer::details::peripheral_latency_state<\n    bluetoe::link_layer::peripheral_latency_configuration<\n        bluetoe::link_layer::peripheral_latency::listen_if_last_received_not_empty\n    >\n>\n{\n    listen_if_last_received_not_empty()\n    {\n        reset_connection_state();\n    }\n};\n\nBOOST_FIXTURE_TEST_SUITE( last_received_not_empty, listen_if_last_received_not_empty )\n\n    static const int latency = 100;\n\n    BOOST_AUTO_TEST_CASE( initial_state )\n    {\n        BOOST_TEST( current_channel_index() == 0u );\n        BOOST_TEST( connection_event_counter() == 0u );\n        BOOST_TEST( time_since_last_event().zero() );\n    }\n\n    BOOST_AUTO_TEST_CASE( following_latency_when_no_event_happend )\n    {\n        plan_next_connection_event(\n            latency, no_events, typical_connection_interval, no_pending_instance );\n\n        BOOST_TEST( current_channel_index() == 101u % 37u );\n        BOOST_TEST( connection_event_counter() == 101u );\n        BOOST_TEST( time_since_last_event() == 101u * typical_connection_interval );\n    }\n\n    BOOST_AUTO_TEST_CASE( take_next_event_if_unacknowlaged_data_was_send )\n    {\n        plan_next_connection_event(\n            latency, last_received_not_empty_events, typical_connection_interval, no_pending_instance );\n\n        BOOST_TEST( current_channel_index() == 1u );\n        BOOST_TEST( connection_event_counter() == 1u );\n        BOOST_TEST( time_since_last_event() == 1 * typical_connection_interval );\n\n        plan_next_connection_event(\n            latency, no_events, typical_connection_interval, no_pending_instance );\n\n        BOOST_TEST( current_channel_index() == 102u % 37u );\n        BOOST_TEST( connection_event_counter() == 102u );\n        BOOST_TEST( time_since_last_event() == 101 * typical_connection_interval );\n\n        plan_next_connection_event_after_timeout(\n            typical_connection_interval );\n\n        BOOST_TEST( current_channel_index() == 103u % 37u );\n        BOOST_TEST( connection_event_counter() == 103u );\n        BOOST_TEST( time_since_last_event() == 102 * typical_connection_interval );\n\n        plan_next_connection_event(\n            latency, all_events, typical_connection_interval, no_pending_instance );\n\n        BOOST_TEST( current_channel_index() == 104u % 37u );\n        BOOST_TEST( connection_event_counter() == 104 );\n        BOOST_TEST( time_since_last_event() == 1 * typical_connection_interval );\n    }\n\n    BOOST_AUTO_TEST_CASE( no_disarm_connection_event_support_required )\n    {\n        BOOST_TEST( reschedule_on_pending_data( *this, typical_connection_interval ) == false );\n    }\n\n    BOOST_AUTO_TEST_CASE( take_next_event_on_error )\n    {\n        plan_next_connection_event(\n            500, last_error_events, typical_connection_interval, no_pending_instance );\n\n        BOOST_TEST( current_channel_index() == 1u );\n        BOOST_TEST( connection_event_counter() == 1u );\n        BOOST_TEST( time_since_last_event() == 1 * typical_connection_interval );\n    }\n\nBOOST_AUTO_TEST_SUITE_END()\n\nstruct listen_if_last_transmitted_not_empty : bluetoe::link_layer::details::peripheral_latency_state<\n    bluetoe::link_layer::peripheral_latency_configuration<\n        bluetoe::link_layer::peripheral_latency::listen_if_last_transmitted_not_empty\n    >\n>\n{\n    listen_if_last_transmitted_not_empty()\n    {\n        reset_connection_state();\n    }\n};\n\nBOOST_FIXTURE_TEST_SUITE( last_transmitted_not_empty, listen_if_last_transmitted_not_empty )\n\n    static const int latency = 1;\n\n    BOOST_AUTO_TEST_CASE( initial_state )\n    {\n        BOOST_TEST( current_channel_index() == 0u );\n        BOOST_TEST( connection_event_counter() == 0u );\n        BOOST_TEST( time_since_last_event().zero() );\n    }\n\n    BOOST_AUTO_TEST_CASE( take_next_event_if_last_transmitted_not_empty )\n    {\n        plan_next_connection_event(\n            latency, no_events, typical_connection_interval, no_pending_instance );\n\n        BOOST_TEST( current_channel_index() == 2u );\n        BOOST_TEST( connection_event_counter() == 2u );\n        BOOST_TEST( time_since_last_event() == 2 * typical_connection_interval );\n\n        plan_next_connection_event(\n            latency, last_transmitted_not_empty_events, typical_connection_interval, no_pending_instance );\n\n        BOOST_TEST( current_channel_index() == 3u );\n        BOOST_TEST( connection_event_counter() == 3u );\n        BOOST_TEST( time_since_last_event() == 1 * typical_connection_interval );\n    }\n\n    BOOST_AUTO_TEST_CASE( no_disarm_connection_event_support_required )\n    {\n        BOOST_TEST( reschedule_on_pending_data( *this, typical_connection_interval ) == false );\n    }\n\n    BOOST_AUTO_TEST_CASE( take_next_event_on_error )\n    {\n        plan_next_connection_event(\n            500, last_error_events, typical_connection_interval, no_pending_instance );\n\n        BOOST_TEST( current_channel_index() == 1u );\n        BOOST_TEST( connection_event_counter() == 1u );\n        BOOST_TEST( time_since_last_event() == 1 * typical_connection_interval );\n    }\n\nBOOST_AUTO_TEST_SUITE_END()\n\nstruct listen_if_last_received_had_more_data : bluetoe::link_layer::details::peripheral_latency_state<\n    bluetoe::link_layer::peripheral_latency_configuration<\n        bluetoe::link_layer::peripheral_latency::listen_if_last_received_had_more_data\n    >\n>\n{\n    listen_if_last_received_had_more_data()\n    {\n        reset_connection_state();\n    }\n};\n\nBOOST_FIXTURE_TEST_SUITE( last_received_had_more_data, listen_if_last_received_had_more_data )\n\n    static const int latency = 2;\n\n    BOOST_AUTO_TEST_CASE( initial_state )\n    {\n        BOOST_TEST( current_channel_index() == 0u );\n        BOOST_TEST( connection_event_counter() == 0u );\n        BOOST_TEST( time_since_last_event().zero() );\n    }\n\n    BOOST_AUTO_TEST_CASE( take_next_event_if_last_received_had_more_data_events )\n    {\n        plan_next_connection_event(\n            latency, no_events, typical_connection_interval, no_pending_instance );\n\n        BOOST_TEST( current_channel_index() == 3u );\n        BOOST_TEST( connection_event_counter() == 3u );\n        BOOST_TEST( time_since_last_event() == 3 * typical_connection_interval );\n\n        plan_next_connection_event(\n            latency, last_received_had_more_data_events, typical_connection_interval, no_pending_instance );\n\n        BOOST_TEST( current_channel_index() == 4u );\n        BOOST_TEST( connection_event_counter() == 4u );\n        BOOST_TEST( time_since_last_event() == 1 * typical_connection_interval );\n    }\n\n    BOOST_AUTO_TEST_CASE( no_disarm_connection_event_support_required )\n    {\n        BOOST_TEST( reschedule_on_pending_data( *this, typical_connection_interval ) == false );\n    }\n\n    BOOST_AUTO_TEST_CASE( take_next_event_on_error )\n    {\n        plan_next_connection_event(\n            500, last_error_events, typical_connection_interval, no_pending_instance );\n\n        BOOST_TEST( current_channel_index() == 1u );\n        BOOST_TEST( connection_event_counter() == 1u );\n        BOOST_TEST( time_since_last_event() == 1 * typical_connection_interval );\n    }\n\nBOOST_AUTO_TEST_SUITE_END()\n\nstruct listen_if_pending_transmit_data : bluetoe::link_layer::details::peripheral_latency_state<\n    bluetoe::link_layer::peripheral_latency_configuration<\n        bluetoe::link_layer::peripheral_latency::listen_if_pending_transmit_data\n    >\n>\n{\n    listen_if_pending_transmit_data()\n        : disarm_connection_event_result( false, bluetoe::link_layer::delta_time() )\n    {\n        reset_connection_state();\n    }\n\n    std::pair< bool, bluetoe::link_layer::delta_time > disarm_connection_event()\n    {\n        return disarm_connection_event_result;\n    }\n\n    std::pair< bool, bluetoe::link_layer::delta_time > disarm_connection_event_result;\n};\n\nBOOST_FIXTURE_TEST_SUITE( pending_transmit_data, listen_if_pending_transmit_data )\n\n    static const int latency = 7;\n\n    BOOST_AUTO_TEST_CASE( initial_state )\n    {\n        BOOST_TEST( current_channel_index() == 0u );\n        BOOST_TEST( connection_event_counter() == 0u );\n        BOOST_TEST( time_since_last_event().zero() );\n    }\n\n    BOOST_AUTO_TEST_CASE( following_latency_when_no_pending_data )\n    {\n        plan_next_connection_event(\n            latency, no_events, typical_connection_interval, no_pending_instance );\n\n        BOOST_TEST( current_channel_index() == 8u );\n        BOOST_TEST( connection_event_counter() == 8u );\n        BOOST_TEST( time_since_last_event() == 8u * typical_connection_interval );\n    }\n\n    BOOST_AUTO_TEST_CASE( take_next_event_if_pending_data_is_present )\n    {\n        plan_next_connection_event(\n            latency, no_events, typical_connection_interval, no_pending_instance );\n\n        BOOST_TEST( current_channel_index() == 8u );\n        BOOST_TEST( connection_event_counter() == 8u );\n        BOOST_TEST( time_since_last_event() == 8 * typical_connection_interval );\n\n        plan_next_connection_event(\n            latency, pending_outgoing_data_events, typical_connection_interval, no_pending_instance );\n\n        BOOST_TEST( current_channel_index() == 9u );\n        BOOST_TEST( connection_event_counter() == 9u );\n        BOOST_TEST( time_since_last_event() == 1 * typical_connection_interval );\n    }\n\n    BOOST_AUTO_TEST_CASE( rescheduling_not_possible )\n    {\n        BOOST_TEST( reschedule_on_pending_data( *this, typical_connection_interval ) == false );\n    }\n\n    BOOST_AUTO_TEST_CASE( initial_connection_event_can_not_be_rescheduled )\n    {\n        disarm_connection_event_result = { true, half_typical_connection_interval };\n        BOOST_TEST( reschedule_on_pending_data( *this, typical_connection_interval ) == false );\n    }\n\n    BOOST_AUTO_TEST_CASE( half_way_to_the_connection_event )\n    {\n        // First, the connection event is planned at the 8th connection event\n        plan_next_connection_event(\n            latency, no_events, typical_connection_interval, no_pending_instance );\n\n        BOOST_TEST( current_channel_index() == 8u );\n        BOOST_TEST( connection_event_counter() == 8u );\n        BOOST_TEST( time_since_last_event() == 8 * typical_connection_interval );\n\n        // now it's moved to 4th\n        disarm_connection_event_result = { true, 3 * typical_connection_interval + half_typical_connection_interval };\n        BOOST_TEST( reschedule_on_pending_data( *this, typical_connection_interval ) == true );\n\n        BOOST_TEST( current_channel_index() == 4u );\n        BOOST_TEST( connection_event_counter() == 4u );\n        BOOST_TEST( time_since_last_event() == 4 * typical_connection_interval );\n    }\n\n    BOOST_AUTO_TEST_CASE( just_after_setting_up_the_connection_event )\n    {\n        // First, the connection event is planned at the 8th connection event\n        plan_next_connection_event(\n            latency, no_events, typical_connection_interval, no_pending_instance );\n\n        BOOST_TEST( current_channel_index() == 8u );\n        BOOST_TEST( connection_event_counter() == 8u );\n        BOOST_TEST( time_since_last_event() == 8 * typical_connection_interval );\n\n        // now it's moved to 4th\n        disarm_connection_event_result = { true, bluetoe::link_layer::delta_time() };\n        BOOST_TEST( reschedule_on_pending_data( *this, typical_connection_interval ) == true );\n\n        BOOST_TEST( current_channel_index() == 1u );\n        BOOST_TEST( connection_event_counter() == 1u );\n        BOOST_TEST( time_since_last_event() == 1 * typical_connection_interval );\n    }\n\n    BOOST_AUTO_TEST_CASE( just_after_setting_up_the_connection_event_without_latency )\n    {\n        // First, the connection event is planned at the 8th connection event\n        plan_next_connection_event(\n            0, no_events, typical_connection_interval, no_pending_instance );\n\n        BOOST_TEST( current_channel_index() == 1u );\n        BOOST_TEST( connection_event_counter() == 1u );\n        BOOST_TEST( time_since_last_event() == 1 * typical_connection_interval );\n\n        // won't move\n        disarm_connection_event_result = { true, bluetoe::link_layer::delta_time() };\n        BOOST_TEST( reschedule_on_pending_data( *this, typical_connection_interval ) == false );\n    }\n\n    BOOST_AUTO_TEST_CASE( new_outgoing_data_directly_after_the_connection_event_was_planned )\n    {\n        plan_next_connection_event(\n            latency, no_events, typical_connection_interval, no_pending_instance );\n\n        BOOST_TEST( current_channel_index() == 8u );\n        BOOST_TEST( connection_event_counter() == 8u );\n        BOOST_TEST( time_since_last_event() == 8 * typical_connection_interval );\n\n        plan_next_connection_event(\n            latency, no_events, typical_connection_interval, no_pending_instance );\n\n        BOOST_TEST( current_channel_index() == 16u );\n        BOOST_TEST( connection_event_counter() == 16u );\n        BOOST_TEST( time_since_last_event() == 8 * typical_connection_interval );\n\n        // now, new outgoing data became pending\n        disarm_connection_event_result = { true, half_typical_connection_interval };\n        BOOST_TEST( reschedule_on_pending_data( *this, typical_connection_interval ) == true );\n\n        BOOST_TEST( current_channel_index() == 9u );\n        BOOST_TEST( connection_event_counter() == 9u );\n        BOOST_TEST( time_since_last_event() == 1 * typical_connection_interval );\n    }\n\n    BOOST_AUTO_TEST_CASE( reschedule_after_connection_instance_overflew )\n    {\n        for ( int i = 0; i != 8192; ++i )\n            plan_next_connection_event(\n                latency, no_events, typical_connection_interval, no_pending_instance );\n\n        BOOST_TEST( current_channel_index() == 9u );\n        BOOST_TEST( connection_event_counter() == 0u );\n        BOOST_TEST( time_since_last_event() == 8 * typical_connection_interval );\n\n        // now, new outgoing data became pending\n        disarm_connection_event_result = { true, half_typical_connection_interval };\n        BOOST_TEST( reschedule_on_pending_data( *this, typical_connection_interval ) == true );\n\n        BOOST_TEST( current_channel_index() == 2u );\n        BOOST_TEST( connection_event_counter() == 0xfff9u );\n        BOOST_TEST( time_since_last_event() == 1 * typical_connection_interval );\n    }\n\n    BOOST_AUTO_TEST_CASE( reschedule_after_channel_index_overflew )\n    {\n        for ( int i = 0; i != 5; ++i )\n            plan_next_connection_event(\n                latency, no_events, typical_connection_interval, no_pending_instance );\n\n        BOOST_TEST( current_channel_index() == 3u );\n        BOOST_TEST( connection_event_counter() == 40u );\n        BOOST_TEST( time_since_last_event() == 8 * typical_connection_interval );\n\n        // now, new outgoing data became pending\n        disarm_connection_event_result = { true, 3 * typical_connection_interval + half_typical_connection_interval };\n        BOOST_TEST( reschedule_on_pending_data( *this, typical_connection_interval ) == true );\n\n        BOOST_TEST( current_channel_index() == 36u );\n        BOOST_TEST( connection_event_counter() == 36u );\n        BOOST_TEST( time_since_last_event() == 4 * typical_connection_interval );\n    }\n\n    // see #97 for more context\n    BOOST_AUTO_TEST_CASE( reschedule_after_applying_very_large_latency )\n    {\n        plan_next_connection_event( 100, no_events, typical_connection_interval, no_pending_instance );\n\n        BOOST_TEST( current_channel_index() == 101u % 37 );\n        BOOST_TEST( connection_event_counter() == 101u );\n        BOOST_TEST( time_since_last_event() == 101 * typical_connection_interval );\n\n        // now, new outgoing data became pending\n        disarm_connection_event_result = { true, 3 * typical_connection_interval + half_typical_connection_interval };\n        BOOST_TEST( reschedule_on_pending_data( *this, typical_connection_interval ) == true );\n\n        BOOST_TEST( current_channel_index() == 4u );\n        BOOST_TEST( connection_event_counter() == 4u );\n        BOOST_TEST( time_since_last_event() == 4 * typical_connection_interval );\n    }\n\n    BOOST_AUTO_TEST_CASE( take_next_event_on_error )\n    {\n        plan_next_connection_event(\n            500, last_error_events, typical_connection_interval, no_pending_instance );\n\n        BOOST_TEST( current_channel_index() == 1u );\n        BOOST_TEST( connection_event_counter() == 1u );\n        BOOST_TEST( time_since_last_event() == 1 * typical_connection_interval );\n    }\n\nBOOST_AUTO_TEST_SUITE_END()\n\nstruct listen_on_multiple_events : bluetoe::link_layer::details::peripheral_latency_state<\n    bluetoe::link_layer::peripheral_latency_configuration<\n        bluetoe::link_layer::peripheral_latency::listen_if_pending_transmit_data,\n        bluetoe::link_layer::peripheral_latency::listen_if_last_transmitted_not_empty\n    >\n>\n{\n    listen_on_multiple_events()\n        : disarm_connection_event_result( false, bluetoe::link_layer::delta_time() )\n    {\n        reset_connection_state();\n\n        // All events, but the ones that are configured to trigger an early connection event\n        // and errors\n        all_but.unacknowledged_data = true;\n        all_but.last_received_not_empty = true;\n        all_but.last_received_had_more_data = true;\n    }\n\n    std::pair< bool, bluetoe::link_layer::delta_time > disarm_connection_event()\n    {\n        return disarm_connection_event_result;\n    }\n\n    std::pair< bool, bluetoe::link_layer::delta_time > disarm_connection_event_result;\n    bluetoe::link_layer::connection_event_events all_but;\n};\n\nBOOST_FIXTURE_TEST_SUITE( combined_connection_event_events, listen_on_multiple_events )\n\n    static const int latency = 1;\n\n    BOOST_AUTO_TEST_CASE( test_for_both_events )\n    {\n        plan_next_connection_event(\n            latency, no_events, typical_connection_interval, no_pending_instance );\n\n        BOOST_TEST( current_channel_index() == 2u );\n        BOOST_TEST( connection_event_counter() == 2u );\n        BOOST_TEST( time_since_last_event() == 2 * typical_connection_interval );\n\n        plan_next_connection_event(\n            latency, all_but, typical_connection_interval, no_pending_instance );\n\n        BOOST_TEST( current_channel_index() == 4u );\n        BOOST_TEST( connection_event_counter() == 4u );\n        BOOST_TEST( time_since_last_event() == 2 * typical_connection_interval );\n\n        plan_next_connection_event(\n            latency, pending_outgoing_data_events, typical_connection_interval, no_pending_instance );\n\n        BOOST_TEST( current_channel_index() == 5u );\n        BOOST_TEST( connection_event_counter() == 5u );\n        BOOST_TEST( time_since_last_event() == 1 * typical_connection_interval );\n\n        plan_next_connection_event(\n            latency, last_transmitted_not_empty_events, typical_connection_interval, no_pending_instance );\n\n        BOOST_TEST( current_channel_index() == 6u );\n        BOOST_TEST( connection_event_counter() == 6u );\n        BOOST_TEST( time_since_last_event() == 1 * typical_connection_interval );\n    }\n\n    BOOST_AUTO_TEST_CASE( latency_limited_by_pending_instance )\n    {\n        plan_next_connection_event(\n            500, no_events, typical_connection_interval, { true, 299u } );\n\n        BOOST_TEST( current_channel_index() == 299u % 37 );\n        BOOST_TEST( connection_event_counter() == 299u );\n        BOOST_TEST( time_since_last_event() == 299u * typical_connection_interval );\n    }\n\n    BOOST_AUTO_TEST_CASE( latency_not_limited_by_pending_instance )\n    {\n        plan_next_connection_event(\n            100, no_events, typical_connection_interval, { true, 299u } );\n\n        BOOST_TEST( current_channel_index() == 101u % 37 );\n        BOOST_TEST( connection_event_counter() == 101u );\n        BOOST_TEST( time_since_last_event() == 101u * typical_connection_interval );\n    }\n\n    BOOST_AUTO_TEST_CASE( latency_limited_by_pending_instance_after_counter_wrap )\n    {\n        for ( int i = 0; i != 130; ++i )\n            plan_next_connection_event(\n                500, no_events, typical_connection_interval, no_pending_instance );\n\n        BOOST_TEST( current_channel_index() == 65130u % 37 );\n        BOOST_TEST( connection_event_counter() == 65130u );\n        BOOST_TEST( time_since_last_event() == 501u * typical_connection_interval );\n\n        plan_next_connection_event(\n            500, no_events, typical_connection_interval, { true, 20 } );\n\n        BOOST_TEST( current_channel_index() == ( 0x10000 + 20u ) % 37 );\n        BOOST_TEST( connection_event_counter() == 20u );\n        BOOST_TEST( time_since_last_event() == ( 0x10000 - 65130u + 20u ) * typical_connection_interval );\n    }\n\nBOOST_AUTO_TEST_SUITE_END()\n\nstruct runtime_configurable : bluetoe::link_layer::details::peripheral_latency_state<\n    bluetoe::link_layer::peripheral_latency_configuration_set<\n        bluetoe::link_layer::peripheral_latency_configuration<\n            bluetoe::link_layer::peripheral_latency::listen_if_pending_transmit_data,\n            bluetoe::link_layer::peripheral_latency::listen_if_last_transmitted_not_empty\n        >,\n        bluetoe::link_layer::peripheral_latency_configuration<\n            bluetoe::link_layer::peripheral_latency::listen_if_pending_transmit_data,\n            bluetoe::link_layer::peripheral_latency::listen_if_last_received_not_empty\n        >\n    >\n>\n{\n    using config1 = bluetoe::link_layer::peripheral_latency_configuration<\n            bluetoe::link_layer::peripheral_latency::listen_if_pending_transmit_data,\n            bluetoe::link_layer::peripheral_latency::listen_if_last_transmitted_not_empty\n        >;\n\n    using config2 = bluetoe::link_layer::peripheral_latency_configuration<\n            bluetoe::link_layer::peripheral_latency::listen_if_pending_transmit_data,\n            bluetoe::link_layer::peripheral_latency::listen_if_last_received_not_empty\n        >;\n\n    runtime_configurable()\n    {\n        reset_connection_state();\n    }\n\n    std::pair< bool, bluetoe::link_layer::delta_time > disarm_connection_event()\n    {\n        return disarm_connection_event_result;\n    }\n\n    std::pair< bool, bluetoe::link_layer::delta_time > disarm_connection_event_result;\n};\n\nBOOST_FIXTURE_TEST_SUITE( switch_behaviour_at_runtime, runtime_configurable )\n\n    static const int latency = 2;\n\n    BOOST_AUTO_TEST_CASE( no_latency )\n    {\n        // a first connection event, without latency or any event\n        plan_next_connection_event(\n            0, no_events, typical_connection_interval, no_pending_instance );\n\n        BOOST_TEST( current_channel_index() == 1u );\n        BOOST_TEST( connection_event_counter() == 1u );\n        BOOST_TEST( time_since_last_event() == 1 * typical_connection_interval );\n    }\n\n    BOOST_AUTO_TEST_CASE( with_latency )\n    {\n        // a first connection event, without latency or any event\n        plan_next_connection_event(\n            latency, no_events, typical_connection_interval, no_pending_instance );\n\n        BOOST_TEST( current_channel_index() == 3u );\n        BOOST_TEST( connection_event_counter() == 3u );\n        BOOST_TEST( time_since_last_event() == 3 * typical_connection_interval );\n    }\n\n    BOOST_AUTO_TEST_CASE( intiatially_the_first_configuration_is_used )\n    {\n        // first configuration reacts to the last_transmit_not_empty\n        plan_next_connection_event(\n            latency, last_transmitted_not_empty_events, typical_connection_interval, no_pending_instance );\n\n        BOOST_TEST( current_channel_index() == 1u );\n        BOOST_TEST( connection_event_counter() == 1u );\n        BOOST_TEST( time_since_last_event() == 1 * typical_connection_interval );\n\n        // but does not react to the last_received_not_empty\n        plan_next_connection_event(\n            latency, last_received_not_empty_events, typical_connection_interval, no_pending_instance );\n\n        BOOST_TEST( current_channel_index() == 4u );\n        BOOST_TEST( connection_event_counter() == 4u );\n        BOOST_TEST( time_since_last_event() == 3 * typical_connection_interval );\n    }\n\n    BOOST_AUTO_TEST_CASE( switching_to_config1_yields_the_same_results )\n    {\n        change_peripheral_latency< config1 >();\n\n        // first configuration reacts to the last_transmit_not_empty\n        plan_next_connection_event(\n            latency, last_transmitted_not_empty_events, typical_connection_interval, no_pending_instance );\n\n        BOOST_TEST( current_channel_index() == 1u );\n        BOOST_TEST( connection_event_counter() == 1u );\n        BOOST_TEST( time_since_last_event() == 1 * typical_connection_interval );\n\n        // but does not react to the last_received_not_empty\n        plan_next_connection_event(\n            latency, last_received_not_empty_events, typical_connection_interval, no_pending_instance );\n\n        BOOST_TEST( current_channel_index() == 4u );\n        BOOST_TEST( connection_event_counter() == 4u );\n        BOOST_TEST( time_since_last_event() == 3 * typical_connection_interval );\n    }\n\n    BOOST_AUTO_TEST_CASE( use_second_configuration )\n    {\n        change_peripheral_latency< config2 >();\n\n        // first configuration reacts to the last_transmit_not_empty\n        plan_next_connection_event(\n            latency, last_transmitted_not_empty_events, typical_connection_interval, no_pending_instance );\n\n        BOOST_TEST( current_channel_index() == 3u );\n        BOOST_TEST( connection_event_counter() == 3u );\n        BOOST_TEST( time_since_last_event() == 3 * typical_connection_interval );\n\n        // but does not react to the last_received_not_empty\n        plan_next_connection_event(\n            latency, last_received_not_empty_events, typical_connection_interval, no_pending_instance );\n\n        BOOST_TEST( current_channel_index() == 4u );\n        BOOST_TEST( connection_event_counter() == 4u );\n        BOOST_TEST( time_since_last_event() == 1 * typical_connection_interval );\n    }\n\n    BOOST_AUTO_TEST_CASE( reschedule )\n    {\n        // First, the connection event is planned at the 8th connection event\n        plan_next_connection_event(\n            latency, no_events, typical_connection_interval, no_pending_instance );\n\n        BOOST_TEST( current_channel_index() == 3u );\n        BOOST_TEST( connection_event_counter() == 3u );\n        BOOST_TEST( time_since_last_event() == 3 * typical_connection_interval );\n\n        disarm_connection_event_result = { true, half_typical_connection_interval };\n        BOOST_TEST( reschedule_on_pending_data( *this, typical_connection_interval ) == true );\n\n        BOOST_TEST( current_channel_index() == 1u );\n        BOOST_TEST( connection_event_counter() == 1u );\n        BOOST_TEST( time_since_last_event() == 1 * typical_connection_interval );\n    }\n\n    BOOST_AUTO_TEST_CASE( latency_limited_by_pending_instance )\n    {\n        plan_next_connection_event(\n            500, no_events, typical_connection_interval, { true, 299u } );\n\n        BOOST_TEST( current_channel_index() == 299u % 37 );\n        BOOST_TEST( connection_event_counter() == 299u );\n        BOOST_TEST( time_since_last_event() == 299u * typical_connection_interval );\n    }\n\n    BOOST_AUTO_TEST_CASE( latency_not_limited_by_pending_instance )\n    {\n        plan_next_connection_event(\n            100, no_events, typical_connection_interval, { true, 299u } );\n\n        BOOST_TEST( current_channel_index() == 101u % 37 );\n        BOOST_TEST( connection_event_counter() == 101u );\n        BOOST_TEST( time_since_last_event() == 101u * typical_connection_interval );\n    }\n\n    BOOST_AUTO_TEST_CASE( latency_limited_by_pending_instance_after_counter_wrap )\n    {\n        for ( int i = 0; i != 130; ++i )\n            plan_next_connection_event(\n                500, no_events, typical_connection_interval, no_pending_instance );\n\n        BOOST_TEST( current_channel_index() == 65130u % 37 );\n        BOOST_TEST( connection_event_counter() == 65130u );\n        BOOST_TEST( time_since_last_event() == 501u * typical_connection_interval );\n\n        plan_next_connection_event(\n            500, no_events, typical_connection_interval, { true, 20 } );\n\n        BOOST_TEST( current_channel_index() == ( 0x10000 + 20u ) % 37 );\n        BOOST_TEST( connection_event_counter() == 20u );\n        BOOST_TEST( time_since_last_event() == ( 0x10000 - 65130u + 20u ) * typical_connection_interval );\n    }\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "tests/link_layer/ring_buffer_tests.cpp",
    "content": "#include <bluetoe/ring_buffer.hpp>\n\n#define BOOST_TEST_MODULE\n#include <boost/test/included/unit_test.hpp>\n\nstruct small_ring : bluetoe::link_layer::pdu_ring_buffer< 50 >\n{\n    small_ring() : bluetoe::link_layer::pdu_ring_buffer< 50 >( &buffer[ 0 ] )\n    {\n    }\n\n    std::uint8_t buffer[ size ];\n};\n\nBOOST_FIXTURE_TEST_CASE( newly_constructed_is_empty, small_ring )\n{\n    BOOST_CHECK_EQUAL( next_end().size, 0u );\n}\n\nBOOST_FIXTURE_TEST_CASE( newly_contructed_contains_not_more_than_one, small_ring )\n{\n    BOOST_CHECK( !more_than_one() );\n}\n\nBOOST_FIXTURE_TEST_CASE( allocating_from_empty, small_ring )\n{\n    BOOST_CHECK_EQUAL( alloc_front( buffer, 30 ).size, 30u );\n}\n\nBOOST_FIXTURE_TEST_CASE( no_room_no_pdu, small_ring )\n{\n    BOOST_CHECK_EQUAL( alloc_front( buffer, 51 ).size, 0u );\n}\n\nBOOST_FIXTURE_TEST_CASE( allocates_the_fist_bytes_of_the_buffer, small_ring )\n{\n    BOOST_CHECK_EQUAL( alloc_front( buffer, 3 ).buffer, buffer );\n    BOOST_CHECK_EQUAL( alloc_front( buffer, 20 ).buffer, buffer );\n    BOOST_CHECK_EQUAL( alloc_front( buffer, 50 ).buffer, buffer );\n}\n\nBOOST_FIXTURE_TEST_CASE( allocating_will_hand_out_different_buffer_positions, small_ring )\n{\n    auto p1 = alloc_front( buffer, 40 );\n    BOOST_CHECK_EQUAL( p1.buffer, buffer );\n    BOOST_CHECK_EQUAL( p1.size, 40u );\n\n    p1.buffer[ 1 ] = 1;\n    push_front( buffer, p1 );\n\n    auto p2 = alloc_front( buffer, 40 );\n    BOOST_CHECK_EQUAL( p2.buffer, &buffer[ 3 ] );\n    BOOST_CHECK_EQUAL( p2.size, 40u );\n\n    p2.buffer[ 1 ] = 18;\n    push_front( buffer, p2 );\n\n    auto p3 = alloc_front( buffer, 15 );\n    BOOST_CHECK_EQUAL( p3.buffer, &buffer[ 23 ] );\n    BOOST_CHECK_EQUAL( p3.size, 15u );\n}\n\nBOOST_FIXTURE_TEST_CASE( storing_at_the_front_will_result_in_allocation_failure, small_ring )\n{\n    auto p1 = alloc_front( buffer, 40 );\n    p1.buffer[ 1 ] = 1;\n    push_front( buffer, p1 );\n\n    auto p2 = alloc_front( buffer, 40 );\n    p2.buffer[ 1 ] = 18;\n    push_front( buffer, p2 );\n\n    BOOST_CHECK_EQUAL( alloc_front( buffer, 30 ).size, 0u );\n}\n\n/*\n * Two elements of size 18 stored at the beginning of the buffer\n */\nstruct full_ring : small_ring\n{\n    full_ring()\n    {\n        auto p1 = alloc_front( buffer, 20 );\n        p1.buffer[ 1 ] = 16;\n        push_front( buffer, p1 );\n\n        auto p2 = alloc_front( buffer, 20 );\n        p2.buffer[ 1 ] = 16;\n        push_front( buffer, p2 );\n\n        BOOST_REQUIRE_EQUAL( alloc_front( buffer, 15 ).size, 0u );\n    }\n};\n\nBOOST_FIXTURE_TEST_CASE( after_freeing_at_the_end_of_a_full_ring_there_is_room_again, full_ring )\n{\n    pop_end( buffer );\n    // if the buffer is splitted, the size of possible allocation is reduced by one\n    BOOST_CHECK_EQUAL( alloc_front( buffer, 17 ).size, 17u );\n    BOOST_CHECK_EQUAL( alloc_front( buffer, 17 ).buffer, buffer );\n}\n\nBOOST_FIXTURE_TEST_CASE( full_ring_contains_more_than_one, full_ring )\n{\n    BOOST_CHECK( more_than_one() );\n}\n\n/*\n * Ring is splitted at pos 36 and empty\n */\nstruct empty_split_ring : full_ring\n{\n    empty_split_ring()\n    {\n        pop_end( buffer );\n        pop_end( buffer );\n    }\n};\n\nBOOST_FIXTURE_TEST_CASE( splited_empty, empty_split_ring )\n{\n    BOOST_CHECK_EQUAL( next_end().size, 0u );\n}\n\nBOOST_FIXTURE_TEST_CASE( when_splitted_full_allocation_not_possible, empty_split_ring )\n{\n    BOOST_CHECK_EQUAL( alloc_front( buffer, 36 ).size, 0u );\n    BOOST_CHECK_EQUAL( alloc_front( buffer, 35 ).size, 35u );\n}\n\nBOOST_FIXTURE_TEST_CASE( empty_split_ring_contains_not_more_than_one, empty_split_ring )\n{\n    BOOST_CHECK( !more_than_one() );\n}\n\n/*\n * After the ring was splitted in the middle, the maximum possible block of 35 bytes are\n * allocated at the end of the ring.\n */\nstruct one_block_at_the_end : empty_split_ring\n{\n    one_block_at_the_end()\n    {\n        auto p = alloc_front( buffer, 35 );\n        p.buffer[ 1 ] = 33;\n        push_front( buffer, p );\n    }\n};\n\nBOOST_FIXTURE_TEST_CASE( max_alloc_front_after_split, one_block_at_the_end )\n{\n    BOOST_CHECK_EQUAL( alloc_front( buffer, 16 ).size, 0u );\n    BOOST_CHECK_EQUAL( alloc_front( buffer, 15 ).size, 15u );\n}\n\nBOOST_FIXTURE_TEST_CASE( access_to_allocated_block_at_the_beginning, one_block_at_the_end )\n{\n    BOOST_CHECK_EQUAL( next_end().size, 35u );\n    BOOST_CHECK_EQUAL( next_end().buffer - &buffer[ 0 ], 0 );\n}\n\nBOOST_FIXTURE_TEST_CASE( one_block_at_the_end_contains_not_more_than_one, one_block_at_the_end )\n{\n    BOOST_CHECK( !more_than_one() );\n}\n\n/*\n * If the allocated chunk is small enough, it will be allocated from the end of the memeory, without wrapping\n */\nstruct one_small_block_at_the_end : empty_split_ring\n{\n    one_small_block_at_the_end()\n    {\n        auto p = alloc_front( buffer, 3 );\n        p.buffer[ 1 ] = 1;\n        push_front( buffer, p );\n    }\n};\n\nBOOST_FIXTURE_TEST_CASE( access_to_allocated_small_block_at_the_end, one_small_block_at_the_end )\n{\n    BOOST_CHECK_EQUAL( next_end().size, 3u );\n    BOOST_CHECK_EQUAL( next_end().buffer - &buffer[ 0 ], 36u );\n}\n\n/*\n * When allocating to the end of the buffer and then pop all elements out of the buffer,\n * the buffer is splitted at the end of the buffer.\n */\nstruct splitted_at_end : one_block_at_the_end\n{\n    splitted_at_end()\n    {\n        auto p = alloc_front( buffer, 15 );\n        p.buffer[ 1 ] = 13;\n        push_front( buffer, p );\n\n        pop_end( buffer );\n        pop_end( buffer );\n    }\n};\n\nBOOST_FIXTURE_TEST_CASE( nearly_max_alloc_from_empty_buffer, splitted_at_end )\n{\n    BOOST_CHECK_EQUAL( alloc_front( buffer, 50 ).size, 0u );\n    BOOST_CHECK_EQUAL( alloc_front( buffer, 49 ).size, 49u );\n}\n"
  },
  {
    "path": "tests/link_layer/signaling_channel_tests.cpp",
    "content": "#define BOOST_TEST_MODULE\n#include <boost/test/included/unit_test.hpp>\n#include <bluetoe/l2cap_signaling_channel.hpp>\n\nstruct channel : bluetoe::l2cap::signaling_channel<>\n{\n    channel()\n        : out_size( sizeof( buffer ) )\n    {\n    }\n\n    void signaling_channel_input( std::initializer_list< std::uint8_t > pdu, std::initializer_list< std::uint8_t > expected )\n    {\n        out_size = sizeof( buffer );\n        signaling_channel::l2cap_input( pdu.begin(), pdu.size(), buffer, out_size, *this );\n\n        BOOST_REQUIRE_EQUAL_COLLECTIONS( expected.begin(), expected.end(), &buffer[ 0 ], &buffer[ out_size ] );\n    }\n\n    void signaling_channel_output( std::initializer_list< std::uint8_t > expected )\n    {\n        out_size = sizeof( buffer );\n        signaling_channel::l2cap_output( buffer, out_size, *this );\n        BOOST_REQUIRE_EQUAL_COLLECTIONS( expected.begin(), expected.end(), &buffer[ 0 ], &buffer[ out_size ] );\n    }\n\n    std::size_t  out_size;\n    std::uint8_t buffer[ 23 ];\n};\n\nBOOST_FIXTURE_TEST_CASE( creates_no_output_by_default, channel )\n{\n    signaling_channel_output( {} );\n}\n\nBOOST_FIXTURE_TEST_CASE( empty_command_to_be_ignored, channel )\n{\n    signaling_channel_input( {}, {} );\n}\n\nBOOST_FIXTURE_TEST_CASE( connection_parameter_update_response_without_request, channel )\n{\n    signaling_channel_input(\n        {\n            0x13, 0x01, 0x02, 0x00, 0x00, 0x00\n        },\n        {\n            0x01, 0x01, 0x02, 0x00, 0x00, 0x00\n        }\n    );\n}\n\nBOOST_FIXTURE_TEST_CASE( command_with_invalid_identifier, channel )\n{\n    signaling_channel_input(\n        {\n            0x14, 0x00, 0x0A, 0x00,\n            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00\n        },\n        {\n        }\n    );\n}\n\nBOOST_FIXTURE_TEST_CASE( connection_parameter_update_request_rejected, channel )\n{\n    signaling_channel_input(\n        {\n            0x12, 0x03, 0x08, 0x00,\n            0x10, 0x00,\n            0x20, 0x00,\n            0x00, 0x00,\n            0x00, 0x01,\n        },\n        {\n            0x01, 0x03, 0x02, 0x00, 0x00, 0x00\n        }\n    );\n}\n\nBOOST_FIXTURE_TEST_CASE( creates_connection_parameter_update_request, channel )\n{\n    connection_parameter_update_request( 0x0020, 0x0100, 0x55, 0xC80 );\n\n    signaling_channel_output( {\n        0x12, 0x01, 0x08, 0x00,\n        0x20, 0x00, 0x00, 0x01,\n        0x55, 0x00, 0x80, 0x0c\n    });\n}\n\nBOOST_FIXTURE_TEST_CASE( second_connection_parameter_update_request_will_not_be_queued, channel )\n{\n    BOOST_CHECK( connection_parameter_update_request( 0x0020, 0x0100, 0x55, 0xC80 ) );\n    BOOST_CHECK( !connection_parameter_update_request( 0x0020, 0x0100, 0x55, 0xC80 ) );\n}\n\nstruct connection_parameter_update_requested : channel\n{\n\n    connection_parameter_update_requested()\n    {\n        connection_parameter_update_request( 0x0020, 0x0100, 0x55, 0xC80 );\n\n        signaling_channel_output( {\n            0x12, 0x01, 0x08, 0x00,\n            0x20, 0x00, 0x00, 0x01,\n            0x55, 0x00, 0x80, 0x0c\n        });\n    }\n};\n\nBOOST_FIXTURE_TEST_CASE( second_connection_parameter_update_request_will_not_be_queued_after_output, connection_parameter_update_requested )\n{\n    BOOST_CHECK( !connection_parameter_update_request( 0x0020, 0x0100, 0x55, 0xC80 ) );\n}\n\nBOOST_FIXTURE_TEST_CASE( no_response_to_connection_parameter_update_response, connection_parameter_update_requested )\n{\n    signaling_channel_input( {\n        0x13, 0x01, 0x02, 0x00,\n        0x00, 0x00\n    },\n    {} );\n}\n\nBOOST_FIXTURE_TEST_CASE( second_connection_parameter_update_request_will_be_queued_after_response, connection_parameter_update_requested )\n{\n    signaling_channel_input( {\n        0x13, 0x01, 0x02, 0x00,\n        0x00, 0x00\n    },\n    {} );\n\n    connection_parameter_update_request( 0x0020, 0x0100, 0x55, 0xC80 );\n\n    signaling_channel_output( {\n        0x12, 0x02, 0x08, 0x00,\n        0x20, 0x00, 0x00, 0x01,\n        0x55, 0x00, 0x80, 0x0c\n    });\n}\n"
  },
  {
    "path": "tests/link_layer/test_radio_tests.cpp",
    "content": "#define BOOST_TEST_MODULE\n#include <boost/test/included/unit_test.hpp>\n\n#include \"test_radio.hpp\"\n\nBOOST_AUTO_TEST_CASE( detect_equal_pdus )\n{\n    BOOST_CHECK( test::check_pdu( { 0x00, 0x01, 0x02 }, { 0x00, 0x01, 0x02 } ) );\n}\n\nBOOST_AUTO_TEST_CASE( detect_unequal_pdus )\n{\n    BOOST_CHECK( !test::check_pdu( { 0x00, 0x01, 0x02 }, { 0x00, 0x01, 0x03 } ) );\n}\n\nBOOST_AUTO_TEST_CASE( detect_unequal_size_pdus )\n{\n    BOOST_CHECK( !test::check_pdu( { 0x00, 0x01, 0x02 }, { 0x00, 0x01 } ) );\n    BOOST_CHECK( !test::check_pdu( { 0x00, 0x01, 0x02 }, { 0x00, 0x01, 0x02, 0x03 } ) );\n}\n\nBOOST_AUTO_TEST_CASE( wild_card )\n{\n    BOOST_CHECK( test::check_pdu( { 0x00, 0x01, 0x02 }, { 0x00, 0x01, test::X } ) );\n    BOOST_CHECK( test::check_pdu( { 0x00, 0x01, 0x02 }, { test::X, 0x01, 0x02 } ) );\n}\n\nBOOST_AUTO_TEST_CASE( and_so_on )\n{\n    BOOST_CHECK( test::check_pdu( { 0x00, 0x01, 0x02 }, { 0x00, test::and_so_on } ) );\n    BOOST_CHECK( test::check_pdu( { 0x00, 0x01, 0x02 }, { 0x00, 0x01, 0x02, test::and_so_on } ) );\n}\n\nBOOST_AUTO_TEST_CASE( mixed_X_and_so_on )\n{\n    BOOST_CHECK(  test::check_pdu( { 0x00, 0x01, 0x02 }, { test::X, 0x01, test::and_so_on } ) );\n    BOOST_CHECK( !test::check_pdu( { 0x00, 0x01, 0x02 }, { test::X, 0x00, test::and_so_on } ) );\n}\n\nBOOST_AUTO_TEST_CASE( pretty_print_empty )\n{\n    BOOST_CHECK_EQUAL( test::pretty_print_pattern( {} ), \"\" );\n}\n\nBOOST_AUTO_TEST_CASE( pretty_print_without_wildcards )\n{\n    BOOST_CHECK_EQUAL( test::pretty_print_pattern( { 0x01, 0x02, 0xaa, 0xff } ), \"01 02 aa ff\" );\n}\n\nBOOST_AUTO_TEST_CASE( pretty_print_with_line_wraps )\n{\n    BOOST_CHECK_EQUAL(\n        test::pretty_print_pattern(\n            {\n                0x01, 0x02, 0xaa, 0xff, 0x01, 0x02, 0xaa, 0xff, 0x01, 0x02, 0xaa, 0xff, 0x01, 0x02, 0xaa, 0xff,\n                0x01, 0x02, 0xaa, 0xff, 0x01, 0x02, 0xaa, 0xff, 0x01, 0x02, 0xaa, 0xff, 0x01, 0x02, 0xaa, 0xff,\n                0x01, 0x02, 0xaa\n            }\n        ),\n        \"01 02 aa ff 01 02 aa ff 01 02 aa ff 01 02 aa ff\\n\"\n        \"01 02 aa ff 01 02 aa ff 01 02 aa ff 01 02 aa ff\\n\"\n        \"01 02 aa\"\n    );\n}\n\nBOOST_AUTO_TEST_CASE( pretty_print_with_wildcards )\n{\n    BOOST_CHECK_EQUAL(\n        test::pretty_print_pattern(\n            {\n                0x01, test::X, 0xaa, 0xff, 0x01, 0x02, test::and_so_on\n            }\n        ),\n        \"01 XX aa ff 01 02 ...\"\n    );\n}"
  },
  {
    "path": "tests/link_layer/white_list_tests.cpp",
    "content": "#include <bluetoe/white_list.hpp>\n\n#define BOOST_TEST_MODULE\n#include <boost/test/included/unit_test.hpp>\n#include <boost/test/unit_test.hpp>\n#include <boost/mpl/list.hpp>\n\n#include <array>\n#include <algorithm>\n\nstruct radio_without_white_list_support {\n    static constexpr std::size_t radio_maximum_white_list_entries = 0;\n};\n\ntemplate < std::size_t Size >\nclass mock_radio_with_white_list_support\n{\npublic:\n    static constexpr std::size_t radio_maximum_white_list_entries = Size;\n\n    mock_radio_with_white_list_support()\n        : free_size_( Size )\n    {}\n\n    std::size_t radio_white_list_free_size() const\n    {\n        return free_size_;\n    }\n\n    void radio_clear_white_list()\n    {\n        free_size_ = Size;\n    }\n\n    bool radio_add_to_white_list( const bluetoe::link_layer::device_address& addr )\n    {\n        if ( radio_is_in_white_list( addr ) )\n            return true;\n\n        if ( free_size_ == 0 )\n            return false;\n\n        list_[ fill_size() ] = addr;\n        --free_size_;\n\n        return true;\n    }\n\n    bool radio_remove_from_white_list( const bluetoe::link_layer::device_address& addr )\n    {\n        auto end = list_.begin() + fill_size();\n        auto pos = std::find( list_.begin(), end, addr );\n\n        if ( pos == end )\n            return false;\n\n        *pos = *( end - 1 );\n        ++free_size_;\n\n        return true;\n    }\n\n    bool radio_is_in_white_list( const bluetoe::link_layer::device_address& addr ) const\n    {\n        auto end = list_.begin() + fill_size();\n        return std::find( list_.begin(), end, addr ) != end;\n    }\n\n    void radio_connection_request_filter( bool b )\n    {\n        connection_request_filter_ = b;\n    }\n\n    bool radio_connection_request_filter() const\n    {\n        return connection_request_filter_;\n    }\n\n    void radio_scan_request_filter( bool b )\n    {\n        scan_request_filter_ = b;\n    }\n\n    bool radio_scan_request_filter() const\n    {\n        return scan_request_filter_;\n    }\n\n    bool radio_is_connection_request_in_filter( const bluetoe::link_layer::device_address& addr ) const\n    {\n        return !connection_request_filter_ || radio_is_in_white_list( addr );\n    }\n\n    bool radio_is_scan_request_in_filter( const bluetoe::link_layer::device_address& addr ) const\n    {\n        return !scan_request_filter_ || radio_is_in_white_list( addr );\n    }\n\nprivate:\n    std::size_t fill_size() const\n    {\n        return Size - free_size_;\n    }\n\n    std::array< bluetoe::link_layer::device_address, Size > list_;\n    std::size_t                                             free_size_;\n    bool                                                    connection_request_filter_;\n    bool                                                    scan_request_filter_;\n};\n\n/*\n * The white list can either be implemented by hardware or by software\n */\n\nstruct only_software\n    : radio_without_white_list_support\n    , bluetoe::link_layer::white_list< 8 >::impl< radio_without_white_list_support, only_software >\n{\n};\n\nstruct only_hardware\n    : mock_radio_with_white_list_support< 8 >\n    , bluetoe::link_layer::white_list< 8 >::impl< mock_radio_with_white_list_support< 8 >, only_hardware >\n{\n};\n\nbluetoe::link_layer::public_device_address addr1( { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 } );\nbluetoe::link_layer::random_device_address addr2( { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 } );\nbluetoe::link_layer::public_device_address addr3( { 0x02, 0x02, 0x03, 0x04, 0x05, 0x06 } );\nbluetoe::link_layer::random_device_address addr4( { 0x02, 0x02, 0x03, 0x04, 0x05, 0x06 } );\nbluetoe::link_layer::public_device_address addr5( { 0x03, 0x02, 0x03, 0x04, 0x05, 0x06 } );\nbluetoe::link_layer::random_device_address addr6( { 0x03, 0x02, 0x03, 0x04, 0x05, 0x06 } );\nbluetoe::link_layer::public_device_address addr7( { 0x04, 0x02, 0x03, 0x04, 0x05, 0x06 } );\nbluetoe::link_layer::random_device_address addr8( { 0x04, 0x02, 0x03, 0x04, 0x05, 0x06 } );\nbluetoe::link_layer::public_device_address addr9( { 0x05, 0x02, 0x03, 0x04, 0x05, 0x06 } );\nbluetoe::link_layer::random_device_address addr10( { 0x05, 0x02, 0x03, 0x04, 0x05, 0x06 } );\n\ntypedef boost::mpl::list<\n    only_software,\n    only_hardware\n> test_types;\n\nBOOST_AUTO_TEST_CASE_TEMPLATE( maximum_white_list_entries_is_provied, T, test_types )\n{\n    BOOST_CHECK_EQUAL( std::size_t(T::maximum_white_list_entries), 8u );\n}\n\nBOOST_AUTO_TEST_CASE_TEMPLATE( reports_the_maximum_number_of_elements_after_default_contructed, T, test_types )\n{\n    T white_list;\n    BOOST_CHECK_EQUAL( white_list.white_list_free_size(), 8u );\n}\n\nBOOST_AUTO_TEST_CASE_TEMPLATE( adding_one_address, T, test_types )\n{\n    T white_list;\n    BOOST_CHECK( white_list.add_to_white_list( addr1 ) );\n    BOOST_CHECK_EQUAL( white_list.white_list_free_size(), 7u );\n}\n\nBOOST_AUTO_TEST_CASE_TEMPLATE( adding_the_same_address, T, test_types )\n{\n    T white_list;\n    BOOST_CHECK( white_list.add_to_white_list( addr1 ) );\n    BOOST_CHECK( white_list.add_to_white_list( addr2 ) );\n    BOOST_CHECK( white_list.add_to_white_list( addr1 ) );\n\n    BOOST_CHECK_EQUAL( white_list.white_list_free_size(), 6u );\n}\n\nBOOST_AUTO_TEST_CASE_TEMPLATE( addr_not_in_list, T, test_types )\n{\n    T white_list;\n    BOOST_CHECK( !white_list.is_in_white_list( addr1 ) );\n}\n\nBOOST_AUTO_TEST_CASE_TEMPLATE( addr_is_in_list, T, test_types )\n{\n    T white_list;\n    white_list.add_to_white_list( addr1 );\n    BOOST_CHECK( white_list.is_in_white_list( addr1 ) );\n}\n\nBOOST_AUTO_TEST_CASE_TEMPLATE( addr_is_in_list2, T, test_types )\n{\n    T white_list;\n    white_list.add_to_white_list( addr1 );\n    white_list.add_to_white_list( addr2 );\n    white_list.add_to_white_list( addr3 );\n    white_list.add_to_white_list( addr4 );\n    white_list.add_to_white_list( addr5 );\n    BOOST_CHECK( white_list.is_in_white_list( addr3 ) );\n    BOOST_CHECK( white_list.is_in_white_list( addr5 ) );\n    BOOST_CHECK( !white_list.is_in_white_list( addr6 ) );\n}\n\nBOOST_AUTO_TEST_CASE_TEMPLATE( remove_from_empty, T, test_types )\n{\n    T white_list;\n    BOOST_CHECK( !white_list.remove_from_white_list( addr1 ) );\n}\n\nBOOST_AUTO_TEST_CASE_TEMPLATE( remove_from_list, T, test_types )\n{\n    T white_list;\n    white_list.add_to_white_list( addr1 );\n    white_list.add_to_white_list( addr2 );\n    white_list.add_to_white_list( addr3 );\n    white_list.add_to_white_list( addr4 );\n    white_list.add_to_white_list( addr5 );\n\n    BOOST_CHECK( white_list.remove_from_white_list( addr1 ) );\n    BOOST_CHECK( white_list.remove_from_white_list( addr5 ) );\n    BOOST_CHECK( !white_list.remove_from_white_list( addr1 ) );\n    BOOST_CHECK( !white_list.remove_from_white_list( addr5 ) );\n\n    BOOST_CHECK( white_list.is_in_white_list( addr2 ) );\n    BOOST_CHECK( white_list.is_in_white_list( addr3 ) );\n    BOOST_CHECK( white_list.is_in_white_list( addr4 ) );\n\n    BOOST_CHECK_EQUAL( white_list.white_list_free_size(), 5u );\n}\n\nBOOST_AUTO_TEST_CASE_TEMPLATE( activate_white_list_function_exists, T, test_types )\n{\n    T white_list;\n    white_list.connection_request_filter( true );\n    white_list.scan_request_filter( true );\n}\n\nBOOST_AUTO_TEST_CASE_TEMPLATE( clear_empty_white_list, T, test_types )\n{\n    T white_list;\n    white_list.clear_white_list();\n    BOOST_CHECK_EQUAL( white_list.white_list_free_size(), 8u );\n}\n\nBOOST_AUTO_TEST_CASE_TEMPLATE( clear_none_empty_white_list, T, test_types )\n{\n    T white_list;\n    white_list.add_to_white_list( addr1 );\n    white_list.add_to_white_list( addr2 );\n\n    white_list.clear_white_list();\n    BOOST_CHECK_EQUAL( white_list.white_list_free_size(), 8u );\n    BOOST_CHECK( !white_list.is_in_white_list( addr1 ) );\n    BOOST_CHECK( !white_list.is_in_white_list( addr2 ) );\n}\n\nBOOST_FIXTURE_TEST_CASE( all_connection_requests_are_in_filter_by_default, only_software )\n{\n    BOOST_CHECK( !connection_request_filter() );\n    BOOST_CHECK( is_connection_request_in_filter( addr1 ) );\n}\n\nBOOST_FIXTURE_TEST_CASE( activation_connection_request_filter, only_software )\n{\n    connection_request_filter( true );\n    BOOST_CHECK( !is_connection_request_in_filter( addr1 ) );\n}\n\nBOOST_FIXTURE_TEST_CASE( deactivation_connection_request_filter, only_software )\n{\n    connection_request_filter( true );\n    connection_request_filter( false );\n    BOOST_CHECK( is_connection_request_in_filter( addr1 ) );\n}\n\nBOOST_FIXTURE_TEST_CASE( address_in_activated_connection_filter, only_software )\n{\n    connection_request_filter( true );\n    add_to_white_list( addr1 );\n    BOOST_CHECK( is_connection_request_in_filter( addr1 ) );\n}\n\nBOOST_FIXTURE_TEST_CASE( all_scan_requests_are_in_filter_by_default, only_software )\n{\n    BOOST_CHECK( !scan_request_filter() );\n    BOOST_CHECK( is_scan_request_in_filter( addr1 ) );\n}\n\nBOOST_FIXTURE_TEST_CASE( activation_scan_request_filter, only_software )\n{\n    scan_request_filter( true );\n    BOOST_CHECK( !is_scan_request_in_filter( addr1 ) );\n}\n\nBOOST_FIXTURE_TEST_CASE( deactivation_scan_request_filter, only_software )\n{\n    scan_request_filter( true );\n    scan_request_filter( false );\n    BOOST_CHECK( is_scan_request_in_filter( addr1 ) );\n}\n\nBOOST_FIXTURE_TEST_CASE( address_in_activated_scan_filter, only_software )\n{\n    scan_request_filter( true );\n    add_to_white_list( addr1 );\n    BOOST_CHECK( is_scan_request_in_filter( addr1 ) );\n}\n"
  },
  {
    "path": "tests/notification_queue_tests.cpp",
    "content": "#include <bluetoe/notification_queue.hpp>\n\n#define BOOST_TEST_MODULE\n#include <boost/test/included/unit_test.hpp>\n\nnamespace {\n    struct empty_fixture {};\n}\n\nusing queue17 = bluetoe::notification_queue< std::tuple< std::integral_constant< int, 17u > >, empty_fixture >;\nusing queue3 = bluetoe::notification_queue< std::tuple< std::integral_constant< int, 3u > >, empty_fixture >;\nusing queue8 = bluetoe::notification_queue< std::tuple< std::integral_constant< int, 8u > >, empty_fixture >;\n\nBOOST_AUTO_TEST_SUITE( single_prio_notifications )\n\n    BOOST_FIXTURE_TEST_CASE( empty_queue, queue17 )\n    {\n        BOOST_CHECK( dequeue_indication_or_confirmation().first == entry_type::empty );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( adding_one_notification, queue17 )\n    {\n        BOOST_CHECK( queue_notification( 12u ) );\n        BOOST_CHECK( ( dequeue_indication_or_confirmation()  == std::pair< entry_type, std::size_t >{ entry_type::notification, 12u } ) );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( dequed_elements_are_removed, queue17 )\n    {\n        BOOST_CHECK( queue_notification( 12u ) );\n        dequeue_indication_or_confirmation();\n        BOOST_CHECK( dequeue_indication_or_confirmation().first == entry_type::empty );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( adding_two_notification, queue17 )\n    {\n        BOOST_CHECK( queue_notification( 12u ) );\n        BOOST_CHECK( queue_notification( 16u ) );\n        BOOST_CHECK( ( dequeue_indication_or_confirmation()  == std::pair< entry_type, std::size_t >{ entry_type::notification, 12u } ) );\n        BOOST_CHECK( ( dequeue_indication_or_confirmation()  == std::pair< entry_type, std::size_t >{ entry_type::notification, 16u } ) );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( adding_notification_twice, queue17 )\n    {\n        BOOST_CHECK( queue_notification( 12u ) );\n        BOOST_CHECK( !queue_notification( 12u ) );\n        BOOST_CHECK( ( dequeue_indication_or_confirmation()  == std::pair< entry_type, std::size_t >{ entry_type::notification, 12u } ) );\n        BOOST_CHECK( dequeue_indication_or_confirmation().first == entry_type::empty );\n    }\n\n    /*\n     * The queue should behave a little bit like a queue and thus not always deliver the same element\n     */\n    BOOST_FIXTURE_TEST_CASE( queue_like, queue17 )\n    {\n        BOOST_CHECK( queue_notification( 12u ) );\n        BOOST_CHECK( queue_notification( 16u ) );\n        BOOST_CHECK( ( dequeue_indication_or_confirmation()  == std::pair< entry_type, std::size_t >{ entry_type::notification, 12u } ) );\n\n        BOOST_CHECK( queue_notification( 12u ) );\n        BOOST_CHECK( ( dequeue_indication_or_confirmation()  == std::pair< entry_type, std::size_t >{ entry_type::notification, 16u } ) );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( wrap_around, queue17 )\n    {\n        BOOST_CHECK( queue_notification( 16u ) );\n        BOOST_CHECK( ( dequeue_indication_or_confirmation()  == std::pair< entry_type, std::size_t >{ entry_type::notification, 16u } ) );\n\n        BOOST_CHECK( queue_notification( 0u ) );\n        BOOST_CHECK( ( dequeue_indication_or_confirmation()  == std::pair< entry_type, std::size_t >{ entry_type::notification, 0u } ) );\n\n        BOOST_CHECK( dequeue_indication_or_confirmation().first == entry_type::empty );\n    }\n\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE( single_prio_indications )\n\n    BOOST_FIXTURE_TEST_CASE( queue_an_indication, queue3 )\n    {\n        BOOST_CHECK( queue_indication( 2 ) );\n        BOOST_CHECK( ( dequeue_indication_or_confirmation()  == std::pair< entry_type, std::size_t >{ entry_type::indication, 2u } ) );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( mixed_notification_and_indications, queue3 )\n    {\n        BOOST_CHECK( queue_notification( 2 ) );\n        BOOST_CHECK( queue_indication( 2 ) );\n        BOOST_CHECK( ( dequeue_indication_or_confirmation()  == std::pair< entry_type, std::size_t >{ entry_type::indication, 2u } ) );\n        BOOST_CHECK( ( dequeue_indication_or_confirmation()  == std::pair< entry_type, std::size_t >{ entry_type::notification, 2u } ) );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( no_indication_until_confirmed, queue17 )\n    {\n        BOOST_CHECK( queue_notification( 12u ) );\n        BOOST_CHECK( queue_indication( 2u ) );\n        BOOST_CHECK( queue_indication( 16u ) );\n\n        BOOST_CHECK( ( dequeue_indication_or_confirmation()  == std::pair< entry_type, std::size_t >{ entry_type::indication, 2u } ) );\n        BOOST_CHECK( ( dequeue_indication_or_confirmation()  == std::pair< entry_type, std::size_t >{ entry_type::notification, 12u } ) );\n        BOOST_CHECK( dequeue_indication_or_confirmation().first == entry_type::empty );\n\n        indication_confirmed();\n        BOOST_CHECK( ( dequeue_indication_or_confirmation()  == std::pair< entry_type, std::size_t >{ entry_type::indication, 16u } ) );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( double_indication_recognized, queue17 )\n    {\n        BOOST_CHECK( queue_indication( 16u ) );\n        BOOST_CHECK( !queue_indication( 16u ) );\n\n        BOOST_CHECK( ( dequeue_indication_or_confirmation()  == std::pair< entry_type, std::size_t >{ entry_type::indication, 16u } ) );\n\n        BOOST_CHECK( queue_indication( 16u ) );\n        BOOST_CHECK( !queue_indication( 16u ) );\n\n        indication_confirmed();\n        BOOST_CHECK( !queue_indication( 16u ) );\n    }\n\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE( single_prio_clearing )\n\n    BOOST_FIXTURE_TEST_CASE( still_empty, queue8 )\n    {\n        clear_indications_and_confirmations();\n        BOOST_CHECK( dequeue_indication_or_confirmation().first == entry_type::empty );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( clear_all, queue3 )\n    {\n        BOOST_CHECK( queue_notification( 2 ) );\n        BOOST_CHECK( queue_indication( 2 ) );\n\n        clear_indications_and_confirmations();\n        BOOST_CHECK( dequeue_indication_or_confirmation().first == entry_type::empty );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( clear_outstanding_confirmation, queue3 )\n    {\n        BOOST_CHECK( queue_indication( 2 ) );\n        BOOST_REQUIRE( ( dequeue_indication_or_confirmation()  == std::pair< entry_type, std::size_t >{ entry_type::indication, 2u } ) );\n\n        clear_indications_and_confirmations();\n\n        BOOST_CHECK( queue_indication( 2 ) );\n        BOOST_CHECK( ( dequeue_indication_or_confirmation()  == std::pair< entry_type, std::size_t >{ entry_type::indication, 2u } ) );\n    }\n\nBOOST_AUTO_TEST_SUITE_END()\n\nusing queue1 = bluetoe::notification_queue< std::tuple< std::integral_constant< int, 1u > >, empty_fixture >;\n\nBOOST_AUTO_TEST_SUITE( single_prio_single_char_notifications )\n\n    BOOST_FIXTURE_TEST_CASE( not_empty, queue1 )\n    {\n        BOOST_CHECK( queue_notification( 0 ) );\n        BOOST_CHECK( !queue_notification( 0 ) );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( dequeue_empty, queue1 )\n    {\n        BOOST_CHECK( ( dequeue_indication_or_confirmation().first == entry_type::empty ) );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( dequeue_not_empty, queue1 )\n    {\n        queue_notification( 0 );\n        BOOST_CHECK( ( dequeue_indication_or_confirmation()  == std::pair< entry_type, std::size_t >{ entry_type::notification, 0 } ) );\n        BOOST_CHECK( ( dequeue_indication_or_confirmation().first == entry_type::empty ) );\n        BOOST_CHECK( queue_notification( 0 ) );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( reset, queue1 )\n    {\n        BOOST_CHECK( queue_notification( 0 ) );\n        clear_indications_and_confirmations();\n        BOOST_CHECK( queue_notification( 0 ) );\n    }\n\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE( single_prio_single_char_indications )\n\n    BOOST_FIXTURE_TEST_CASE( no_empty, queue1 )\n    {\n        BOOST_CHECK( queue_indication( 0 ) );\n        BOOST_CHECK( !queue_indication( 0 ) );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( dequeue_not_empty, queue1 )\n    {\n        queue_indication( 0 );\n        BOOST_CHECK( ( dequeue_indication_or_confirmation()  == std::pair< entry_type, std::size_t >{ entry_type::indication, 0 } ) );\n        BOOST_CHECK( ( dequeue_indication_or_confirmation().first == entry_type::empty ) );\n        BOOST_CHECK( queue_indication( 0 ) );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( confirm_indication, queue1 )\n    {\n        queue_indication( 0 );\n        BOOST_CHECK( ( dequeue_indication_or_confirmation()  == std::pair< entry_type, std::size_t >{ entry_type::indication, 0 } ) );\n        BOOST_CHECK( ( dequeue_indication_or_confirmation().first == entry_type::empty ) );\n        BOOST_CHECK( queue_indication( 0 ) );\n\n        indication_confirmed();\n        BOOST_CHECK( !queue_indication( 0 ) );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( reset, queue1 )\n    {\n        BOOST_CHECK( queue_indication( 0 ) );\n        clear_indications_and_confirmations();\n        BOOST_CHECK( queue_indication( 0 ) );\n    }\n\nBOOST_AUTO_TEST_SUITE_END()\n\nusing queue1_2 = bluetoe::notification_queue<\n    std::tuple<\n        std::integral_constant< int, 1u >,\n        std::integral_constant< int, 2u >\n    >, empty_fixture >;\n\nBOOST_AUTO_TEST_SUITE( mixed_priorities )\n\n    BOOST_FIXTURE_TEST_CASE( queue_empty, queue1_2 )\n    {\n        BOOST_CHECK( ( dequeue_indication_or_confirmation().first == entry_type::empty ) );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( higher_prio, queue1_2 )\n    {\n        BOOST_CHECK( queue_notification( 2 ) );\n        BOOST_CHECK( !queue_notification( 2 ) );\n        BOOST_CHECK( queue_notification( 1 ) );\n        BOOST_CHECK( !queue_notification( 1 ) );\n        BOOST_CHECK( queue_notification( 0 ) );\n        BOOST_CHECK( !queue_notification( 0 ) );\n\n        BOOST_CHECK( ( dequeue_indication_or_confirmation()  == std::pair< entry_type, std::size_t >{ entry_type::notification, 0 } ) );\n        BOOST_CHECK( queue_notification( 0 ) );\n\n        BOOST_CHECK( ( dequeue_indication_or_confirmation()  == std::pair< entry_type, std::size_t >{ entry_type::notification, 0 } ) );\n        BOOST_CHECK( ( dequeue_indication_or_confirmation()  == std::pair< entry_type, std::size_t >{ entry_type::notification, 1 } ) );\n        BOOST_CHECK( ( dequeue_indication_or_confirmation()  == std::pair< entry_type, std::size_t >{ entry_type::notification, 2 } ) );\n        BOOST_CHECK( ( dequeue_indication_or_confirmation().first == entry_type::empty ) );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( outstanding_indication_blocks_new_indiciation, queue1_2 )\n    {\n        BOOST_CHECK( queue_notification( 2 ) );\n        BOOST_CHECK( !queue_notification( 2 ) );\n        BOOST_CHECK( queue_indication( 1 ) );\n        BOOST_CHECK( !queue_indication( 1 ) );\n\n        BOOST_CHECK( ( dequeue_indication_or_confirmation()  == std::pair< entry_type, std::size_t >{ entry_type::indication, 1 } ) );\n        BOOST_CHECK( ( dequeue_indication_or_confirmation()  == std::pair< entry_type, std::size_t >{ entry_type::notification, 2 } ) );\n\n        BOOST_CHECK( queue_indication( 0 ) );\n        BOOST_CHECK( ( dequeue_indication_or_confirmation().first == entry_type::empty ) );\n    }\n\n    // there was a bug in the implementation, where a class derived from all the elements\n    using queue1_1_2 = bluetoe::notification_queue<\n    std::tuple<\n        std::integral_constant< int, 1u >,\n        std::integral_constant< int, 1u >,\n        std::integral_constant< int, 2u >\n    >, empty_fixture >;\n\n    BOOST_FIXTURE_TEST_CASE( implementation_without_ambiguous_base_classes, queue1_1_2 )\n    {\n        // just make sure, that this case compiles\n    }\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "tests/options_tests.cpp",
    "content": "#include <bluetoe/meta_tools.hpp>\n#include <string>\n\n#define BOOST_TEST_MODULE\n#include <boost/test/included/unit_test.hpp>\n\n#include <type_traits>\n\ntemplate < typename >\nstruct template_a {};\n\ntemplate < typename >\nstruct template_b {};\n\nBOOST_AUTO_TEST_CASE( select_type )\n{\n    BOOST_CHECK( ( std::is_same< typename bluetoe::details::select_type< true, int, bool >::type, int >::value ) );\n    BOOST_CHECK( ( std::is_same< typename bluetoe::details::select_type< false, int, bool >::type, bool >::value ) );\n}\n\nBOOST_AUTO_TEST_CASE( select_template_t1 )\n{\n    BOOST_CHECK( (\n        std::is_same<\n            bluetoe::details::select_template_t1< true, template_a, template_b >::template type< int >,\n            template_a< int > >::value\n    ) );\n\n    BOOST_CHECK( (\n        std::is_same<\n            bluetoe::details::select_template_t1< false, template_a, template_b >::template type< int >,\n            template_b< int > >::value\n    ) );\n\n}\n\nBOOST_AUTO_TEST_CASE( or_type )\n{\n    BOOST_CHECK( ( std::is_same< bluetoe::details::or_type< int, char, long >::type, char >::value ) );\n    BOOST_CHECK( ( std::is_same< bluetoe::details::or_type< int, int, long >::type, long >::value ) );\n    BOOST_CHECK( ( std::is_same< bluetoe::details::or_type< int, int, int >::type, int >::value ) );\n}\n\nBOOST_AUTO_TEST_CASE( not_type )\n{\n    BOOST_CHECK( !( bluetoe::details::not_type< std::true_type >::type::value ) );\n    BOOST_CHECK( ( bluetoe::details::not_type< std::false_type >::type::value ) );\n}\n\nnamespace {\n\n    struct meta1 {};\n    struct meta2 {};\n    struct meta3 {};\n    struct meta4 {};\n\n    struct meta1a : meta1 {};\n\n    struct meta12 : meta1, meta2 {};\n\n    struct type1 {\n        typedef meta1 meta_type;\n\n        static std::string name() {\n            return \"type1\";\n        }\n    };\n\n    struct type1a {\n        typedef meta1a meta_type;\n\n        static std::string name() {\n            return \"type1a\";\n        }\n    };\n\n    struct type12 {\n        typedef meta12 meta_type;\n\n        static std::string name() {\n            return \"type12\";\n        }\n    };\n\n    struct type11 {\n        typedef meta1 meta_type;\n\n        static std::string name() {\n            return \"type11\";\n        }\n    };\n\n    struct type2 {\n        typedef meta2 meta_type;\n\n        static std::string name() {\n            return \"type2\";\n        }\n    };\n\n    struct type3 {\n        typedef meta3 meta_type;\n\n        static std::string name() {\n            return \"type3\";\n        }\n    };\n\n    struct type4 {};\n}\n\nBOOST_AUTO_TEST_CASE( extract_meta_type )\n{\n    BOOST_CHECK( (\n        std::is_same<\n            typename bluetoe::details::extract_meta_type< type1 >::meta_type,\n            meta1\n        >::value ) );\n\n    BOOST_CHECK( ( bluetoe::details::extract_meta_type< type1 >::has_meta_type::value ) );\n\n    BOOST_CHECK( (\n        std::is_same<\n            typename bluetoe::details::extract_meta_type< type4 >::meta_type,\n            bluetoe::details::no_such_type\n        >::value ) );\n\n    BOOST_CHECK( ( !bluetoe::details::extract_meta_type< type4 >::has_meta_type::value ) );\n}\n\nBOOST_AUTO_TEST_CASE( find_meta_type_in_empty_list )\n{\n    BOOST_CHECK( ( std::is_same< typename bluetoe::details::find_by_meta_type< meta1 >::type, bluetoe::details::no_such_type >::value ) );\n}\n\nBOOST_AUTO_TEST_CASE( find_meta_type_first_and_only_element )\n{\n    BOOST_CHECK( (\n        std::is_same< typename bluetoe::details::find_by_meta_type< meta1, type1 >::type, type1 >::value ) );\n\n    BOOST_CHECK( (\n        std::is_same< typename bluetoe::details::find_by_meta_type< meta1, type1a >::type, type1a >::value ) );\n\n    BOOST_CHECK( (\n        std::is_same< typename bluetoe::details::find_by_meta_type< meta1, type12 >::type, type12 >::value ) );\n\n    BOOST_CHECK( (\n        std::is_same< typename bluetoe::details::find_by_meta_type< meta1, type2 >::type, bluetoe::details::no_such_type >::value ) );\n\n    BOOST_CHECK( (\n        std::is_same< typename bluetoe::details::find_by_meta_type< meta1, type4 >::type, bluetoe::details::no_such_type >::value ) );\n}\n\nBOOST_AUTO_TEST_CASE( find_meta_type_in_larger_list )\n{\n    BOOST_CHECK( (\n        std::is_same< typename bluetoe::details::find_by_meta_type< meta1, type1, type2 >::type, type1 >::value ) );\n\n    BOOST_CHECK( (\n        std::is_same< typename bluetoe::details::find_by_meta_type< meta1, type2, type1, type3 >::type, type1 >::value ) );\n\n    BOOST_CHECK( (\n        std::is_same< typename bluetoe::details::find_by_meta_type< meta1, type2, type3, type4, type1  >::type, type1 >::value ) );\n\n    BOOST_CHECK( (\n        std::is_same< typename bluetoe::details::find_by_meta_type< meta1, type2, type3, type4, type1, type11 >::type, type1 >::value ) );\n\n    BOOST_CHECK( (\n        std::is_same< typename bluetoe::details::find_by_meta_type< meta1, type2, type3, type4, type1 >::type, type1 >::value ) );\n\n    BOOST_CHECK( (\n        std::is_same< typename bluetoe::details::find_by_meta_type< meta1, type2, type3, type4 >::type, bluetoe::details::no_such_type >::value ) );\n}\n\nBOOST_AUTO_TEST_CASE( find_by_not_meta_type_in_empty_list )\n{\n    BOOST_CHECK( ( std::is_same< typename bluetoe::details::find_by_not_meta_type< meta1 >::type, bluetoe::details::no_such_type >::value ) );\n}\n\nBOOST_AUTO_TEST_CASE( find_by_not_meta_type_in_one_element )\n{\n    BOOST_CHECK( (\n        std::is_same<\n            typename bluetoe::details::find_by_not_meta_type< meta1, type1 >::type,\n            bluetoe::details::no_such_type\n        >::value\n    ) );\n\n    BOOST_CHECK( (\n        std::is_same<\n            typename bluetoe::details::find_by_not_meta_type< meta1, type2 >::type,\n            type2\n        >::value\n    ) );\n\n    BOOST_CHECK( (\n        std::is_same<\n            typename bluetoe::details::find_by_not_meta_type< meta1, type12 >::type,\n            bluetoe::details::no_such_type\n        >::value\n    ) );\n}\n\nBOOST_AUTO_TEST_CASE( find_by_not_meta_type_in_list )\n{\n    BOOST_CHECK( (\n        std::is_same<\n            typename bluetoe::details::find_by_not_meta_type< meta1, type1, type2, type12 >::type,\n            type2\n        >::value\n    ) );\n\n    BOOST_CHECK( (\n        std::is_same<\n            typename bluetoe::details::find_by_not_meta_type< meta1, type1, type12 >::type,\n            bluetoe::details::no_such_type\n        >::value\n    ) );\n\n    BOOST_CHECK( (\n        std::is_same<\n            typename bluetoe::details::find_by_not_meta_type< meta1, type2, type3 >::type,\n            type2\n        >::value\n    ) );\n}\n\nBOOST_AUTO_TEST_CASE( count_by_meta_type_in_empty_list )\n{\n    BOOST_CHECK_EQUAL( ( bluetoe::details::count_by_meta_type< meta1 >::count ), 0 );\n}\n\nBOOST_AUTO_TEST_CASE( count_by_meta_type )\n{\n    BOOST_CHECK_EQUAL( ( bluetoe::details::count_by_meta_type< meta1, type1 >::count ), 1 );\n    BOOST_CHECK_EQUAL( ( bluetoe::details::count_by_meta_type< meta1, type2 >::count ), 0 );\n    BOOST_CHECK_EQUAL( ( bluetoe::details::count_by_meta_type< meta1, type1, type2 >::count ), 1 );\n    BOOST_CHECK_EQUAL( ( bluetoe::details::count_by_meta_type< meta1, type2, type1 >::count ), 1 );\n    BOOST_CHECK_EQUAL( ( bluetoe::details::count_by_meta_type< meta1, type4, type1, type3, type1 >::count ), 2 );\n    BOOST_CHECK_EQUAL( ( bluetoe::details::count_by_meta_type< meta1, type4, type3, type2 >::count ), 0 );\n\n    BOOST_CHECK_EQUAL( ( bluetoe::details::count_by_meta_type< meta1, type1, type3, type2, type12 >::count ), 2 );\n}\n\nBOOST_AUTO_TEST_CASE( option_is_not_set_in_an_empty_list )\n{\n    BOOST_CHECK( !bluetoe::details::has_option< int >::value );\n}\n\nBOOST_AUTO_TEST_CASE( option_is_set )\n{\n    BOOST_CHECK( !( bluetoe::details::has_option< int, char >::value ) );\n    BOOST_CHECK( !( bluetoe::details::has_option< int, char, float >::value ) );\n    BOOST_CHECK( !( bluetoe::details::has_option< int, char, float, bool >::value ) );\n\n    BOOST_CHECK( ( bluetoe::details::has_option< int, char, int >::value ) );\n    BOOST_CHECK( ( bluetoe::details::has_option< int, int, char >::value ) );\n    BOOST_CHECK( ( bluetoe::details::has_option< int, char, int, char >::value ) );\n}\n\nBOOST_AUTO_TEST_CASE( find_all_by_meta_type_empty_list )\n{\n    BOOST_CHECK( ( std::is_same<\n        typename bluetoe::details::find_all_by_meta_type< int >::type, std::tuple<> >::value ) );\n}\n\nBOOST_AUTO_TEST_CASE( find_all_by_meta_type )\n{\n    // no resulting element\n    BOOST_CHECK( ( std::is_same<\n        typename bluetoe::details::find_all_by_meta_type< meta1, type2, type3 >::type,\n        std::tuple<> >::value ) );\n\n    // one resulting element\n    BOOST_CHECK( ( std::is_same<\n        typename bluetoe::details::find_all_by_meta_type< meta1, type2, type3, type1 >::type,\n        std::tuple< type1 > >::value ) );\n\n    BOOST_CHECK( ( std::is_same<\n        typename bluetoe::details::find_all_by_meta_type< meta1, type2, type1, type3 >::type,\n        std::tuple< type1 > >::value ) );\n\n    BOOST_CHECK( ( std::is_same<\n        typename bluetoe::details::find_all_by_meta_type< meta1, type1, type3, type2 >::type,\n        std::tuple< type1 > >::value ) );\n\n    BOOST_CHECK( ( std::is_same<\n        typename bluetoe::details::find_all_by_meta_type< meta1, type1 >::type,\n        std::tuple< type1 > >::value ) );\n\n    BOOST_CHECK( ( std::is_same<\n        typename bluetoe::details::find_all_by_meta_type< meta1, type1a, type3, type2 >::type,\n        std::tuple< type1a > >::value ) );\n\n    BOOST_CHECK( ( std::is_same<\n        typename bluetoe::details::find_all_by_meta_type< meta1, type12 >::type,\n        std::tuple< type12 > >::value ) );\n\n    // more than one result elements\n    BOOST_CHECK( ( std::is_same<\n        typename bluetoe::details::find_all_by_meta_type< meta1, type11, type2, type3, type12, type1 >::type,\n        std::tuple< type11, type12, type1 > >::value ) );\n\n    BOOST_CHECK( ( std::is_same<\n        typename bluetoe::details::find_all_by_meta_type< meta1, type2, type1a, type11, type3 >::type,\n        std::tuple< type1a, type11 > >::value ) );\n\n    BOOST_CHECK( ( std::is_same<\n        typename bluetoe::details::find_all_by_meta_type< meta1, type1, type3, type11, type2 >::type,\n        std::tuple< type1, type11 > >::value ) );\n}\n\nBOOST_AUTO_TEST_CASE( find_all_not_by_meta_type_empty_list )\n{\n    BOOST_CHECK( ( std::is_same<\n        typename bluetoe::details::find_all_by_meta_type< int >::type, std::tuple<> >::value ) );\n}\n\nBOOST_AUTO_TEST_CASE( find_all_not_by_meta_type )\n{\n    // no resulting element\n    BOOST_CHECK( ( std::is_same<\n        typename bluetoe::details::find_all_by_not_meta_type< meta1, type2, type3 >::type,\n        std::tuple< type2, type3 > >::value ) );\n\n    // one resulting element\n    BOOST_CHECK( ( std::is_same<\n        typename bluetoe::details::find_all_by_not_meta_type< meta1, type2, type3, type1 >::type,\n        std::tuple< type2, type3 > >::value ) );\n\n    BOOST_CHECK( ( std::is_same<\n        typename bluetoe::details::find_all_by_not_meta_type< meta1, type2, type1, type3 >::type,\n        std::tuple< type2, type3 > >::value ) );\n\n    BOOST_CHECK( ( std::is_same<\n        typename bluetoe::details::find_all_by_not_meta_type< meta1, type1, type3, type2 >::type,\n        std::tuple< type3, type2 > >::value ) );\n\n    BOOST_CHECK( ( std::is_same<\n        typename bluetoe::details::find_all_by_not_meta_type< meta1, type1 >::type,\n        std::tuple<> >::value ) );\n\n    BOOST_CHECK( ( std::is_same<\n        typename bluetoe::details::find_all_by_not_meta_type< meta1, type1a, type3, type2 >::type,\n        std::tuple< type3, type2 > >::value ) );\n\n    BOOST_CHECK( ( std::is_same<\n        typename bluetoe::details::find_all_by_not_meta_type< meta1, type12 >::type,\n        std::tuple<> >::value ) );\n\n    BOOST_CHECK( ( std::is_same<\n        typename bluetoe::details::find_all_by_not_meta_type< meta1, type11, type2, type3, type12, type1 >::type,\n        std::tuple< type2, type3 > >::value ) );\n\n    BOOST_CHECK( ( std::is_same<\n        typename bluetoe::details::find_all_by_not_meta_type< meta1, type2, type1a, type11, type3 >::type,\n        std::tuple< type2, type3 > >::value ) );\n\n    BOOST_CHECK( ( std::is_same<\n        typename bluetoe::details::find_all_by_not_meta_type< meta1, type1, type3, type11, type2 >::type,\n        std::tuple< type3, type2 > >::value ) );\n}\n\nnamespace {\n    typedef std::vector< std::string > string_list;\n\n    struct register_calls\n    {\n        explicit register_calls( string_list& l ) : list( l )\n        {\n        }\n\n        template< typename O >\n        void each()\n        {\n            list.push_back( O::name() );\n        }\n\n        string_list& list;\n    };\n\n    struct count_calls\n    {\n        explicit count_calls( int& c ) : counts( c )\n        {\n        }\n\n        template< typename O >\n        void each()\n        {\n            ++counts;\n        }\n\n        int& counts;\n    };\n}\n\nBOOST_AUTO_TEST_CASE( for_each_empty )\n{\n    string_list list;\n\n    bluetoe::details::for_<>::each( register_calls( list ) );\n\n    BOOST_CHECK( list.empty() );\n}\n\nBOOST_AUTO_TEST_CASE( for_each_one_element )\n{\n    string_list list;\n\n    bluetoe::details::for_< type1 >::each( register_calls( list ) );\n\n    const string_list expected_result = { \"type1\" };\n\n    BOOST_CHECK_EQUAL_COLLECTIONS( list.begin(), list.end(), expected_result.begin(), expected_result.end() );\n}\n\nBOOST_AUTO_TEST_CASE( for_each_many_elements )\n{\n    string_list list;\n\n    bluetoe::details::for_< type1, type1, type2, type3 >::each( register_calls( list ) );\n\n    const string_list expected_result = { \"type1\", \"type1\", \"type2\", \"type3\" };\n\n    BOOST_CHECK_EQUAL_COLLECTIONS( list.begin(), list.end(), expected_result.begin(), expected_result.end() );\n}\n\nBOOST_AUTO_TEST_CASE( for_each_feed_by_an_tuple )\n{\n    string_list list;\n\n    bluetoe::details::for_< std::tuple< type1, type1, type2, type3 > >::each( register_calls( list ) );\n\n    const string_list expected_result = { \"type1\", \"type1\", \"type2\", \"type3\" };\n\n    BOOST_CHECK_EQUAL_COLLECTIONS( list.begin(), list.end(), expected_result.begin(), expected_result.end() );\n}\n\nBOOST_AUTO_TEST_CASE( for_each_over_tuple_of_empty_tuple )\n{\n    int count = 0;\n\n    bluetoe::details::for_<\n        std::tuple<\n            std::tuple<>\n        > >::each( count_calls( count ) );\n\n    BOOST_CHECK_EQUAL( count, 1 );\n}\n\nBOOST_AUTO_TEST_CASE( for_each_over_tuple_of_tuples )\n{\n    int count = 0;\n\n    bluetoe::details::for_<\n        std::tuple<\n            std::tuple< int, char >,\n            std::tuple< bool, double >\n        > >::each( count_calls( count ) );\n\n    BOOST_CHECK_EQUAL( count, 2 );\n}\n\nBOOST_AUTO_TEST_CASE( group_by_meta_type_empty )\n{\n    BOOST_CHECK( ( std::is_same<\n        typename bluetoe::details::group_by_meta_types< std::tuple<> >::type,\n        std::tuple<> >::value ) );\n\n    BOOST_CHECK( ( std::is_same<\n        typename bluetoe::details::group_by_meta_types< std::tuple<>, meta1 >::type,\n        std::tuple< std::tuple< meta1 > > >::value ) );\n\n    BOOST_CHECK( ( std::is_same<\n        typename bluetoe::details::group_by_meta_types< std::tuple<>, meta1, meta2 >::type,\n        std::tuple< std::tuple< meta1 >, std::tuple< meta2 > > >::value ) );\n}\n\nBOOST_AUTO_TEST_CASE( group_by_meta_type )\n{\n    BOOST_CHECK( ( std::is_same<\n        typename bluetoe::details::group_by_meta_types< std::tuple< type1, type2, type3 > >::type,\n        std::tuple<> >::value ) );\n\n    BOOST_CHECK( ( std::is_same<\n        typename bluetoe::details::group_by_meta_types< std::tuple< type1, type2, type3, type12 >, meta1 >::type,\n        std::tuple< std::tuple< meta1, type1, type12 > > >::value ) );\n\n    BOOST_CHECK( ( std::is_same<\n        typename bluetoe::details::group_by_meta_types< std::tuple< type1, type2, type3, type12 >, meta1, meta2 >::type,\n        std::tuple< std::tuple< meta1, type1, type12 >, std::tuple< meta2, type2, type12 > > >::value ) );\n\n    BOOST_CHECK( ( std::is_same<\n        typename bluetoe::details::group_by_meta_types< std::tuple< type1, type2, type3, type12 >, meta1, meta2, meta4 >::type,\n        std::tuple< std::tuple< meta1, type1, type12 >, std::tuple< meta2, type2, type12 >, std::tuple< meta4 > > >::value ) );\n}\n\nBOOST_AUTO_TEST_CASE( group_by_meta_types_without_empty_groups )\n{\n\n    BOOST_CHECK( ( std::is_same<\n        typename bluetoe::details::group_by_meta_types_without_empty_groups< std::tuple< type1, type2, type3 > >::type,\n        std::tuple<> >::value ) );\n\n    BOOST_CHECK( (\n        std::is_same<\n            typename bluetoe::details::group_by_meta_types_without_empty_groups<\n                std::tuple< type1, type2, type3, type12 >,\n                meta1, meta2, meta4\n            >::type,\n            std::tuple< std::tuple< meta1, type1, type12 >, std::tuple< meta2, type2, type12 > >\n        >::value ) );\n}\n\nBOOST_AUTO_TEST_CASE( remove_if_equal )\n{\n    BOOST_CHECK( ( std::is_same<\n        typename bluetoe::details::remove_if_equal< std::tuple<>, int >::type,\n        std::tuple<> >::value ) );\n\n    BOOST_CHECK( ( std::is_same<\n        typename bluetoe::details::remove_if_equal< std::tuple< int >, int >::type,\n        std::tuple<> >::value ) );\n\n    BOOST_CHECK( ( std::is_same<\n        typename bluetoe::details::remove_if_equal< std::tuple< float >, int >::type,\n        std::tuple< float > >::value ) );\n\n    BOOST_CHECK( ( std::is_same<\n        typename bluetoe::details::remove_if_equal< std::tuple< float, double, int, int, char >, int >::type,\n        std::tuple< float, double, char > >::value ) );\n\n    BOOST_CHECK( ( std::is_same<\n        typename bluetoe::details::remove_if_equal< std::tuple< int, float, double, char, int >, int >::type,\n        std::tuple< float, double, char > >::value ) );\n}\n\nnamespace {\n    template < class T >\n    struct templ {};\n\n    template < class T >\n    struct other_templ {};\n}\n\nBOOST_AUTO_TEST_CASE( remove_if_with_one_wildcard )\n{\n    typedef templ< bluetoe::details::wildcard > with_wildcard;\n\n    BOOST_CHECK( ( std::is_same<\n        typename bluetoe::details::remove_if_equal< std::tuple<>, with_wildcard >::type,\n        std::tuple<> >::value ) );\n\n    BOOST_CHECK( ( std::is_same<\n        typename bluetoe::details::remove_if_equal< std::tuple< int >, with_wildcard >::type,\n        std::tuple< int > >::value ) );\n\n    BOOST_CHECK( ( std::is_same<\n        typename bluetoe::details::remove_if_equal< std::tuple< int, other_templ< int > >, with_wildcard >::type,\n        std::tuple< int, other_templ< int > > >::value ) );\n\n    BOOST_CHECK( ( std::is_same<\n        typename bluetoe::details::remove_if_equal< std::tuple< templ< char >, int, templ< int > >, with_wildcard >::type,\n        std::tuple< int > >::value ) );\n\n   BOOST_CHECK( ( std::is_same<\n        typename bluetoe::details::remove_if_equal< std::tuple< std::tuple< int > >, std::tuple< bluetoe::details::wildcard > >::type,\n        std::tuple<> >::value ) );\n\n   BOOST_CHECK( ( std::is_same<\n        typename bluetoe::details::remove_if_equal< std::tuple< int, std::tuple< int, int >, std::tuple< int > >, std::tuple< bluetoe::details::wildcard > >::type,\n        std::tuple< int, std::tuple< int, int > > >::value ) );\n\n   BOOST_CHECK( ( std::is_same<\n        typename bluetoe::details::remove_if_equal<\n            std::tuple< std::tuple< meta1, type1, type12 >, std::tuple< meta2, type2, type12 >, std::tuple< meta4 > >,\n            std::tuple< bluetoe::details::wildcard >\n        >::type,\n        std::tuple< std::tuple< meta1, type1, type12 >, std::tuple< meta2, type2, type12 > > >::value ) );\n\n}\n\nnamespace {\n    template < typename T >\n    struct is_int : std::false_type {};\n\n    template <>\n    struct is_int< int > : std::true_type {};\n}\n\nBOOST_AUTO_TEST_CASE( count_if )\n{\n    BOOST_CHECK_EQUAL( ( bluetoe::details::count_if< std::tuple<>, is_int >::value ), 0 );\n\n    BOOST_CHECK_EQUAL( ( bluetoe::details::count_if< std::tuple< int >, is_int >::value ), 1 );\n\n    BOOST_CHECK_EQUAL( ( bluetoe::details::count_if< std::tuple< char >, is_int >::value ), 0 );\n\n    BOOST_CHECK_EQUAL( ( bluetoe::details::count_if< std::tuple< int, char, int >, is_int >::value ), 2 );\n\n    BOOST_CHECK_EQUAL( ( bluetoe::details::count_if< std::tuple< char, bool, int, float >, is_int >::value ), 1 );\n\n    BOOST_CHECK_EQUAL( ( bluetoe::details::count_if< std::tuple< char, int >, is_int >::value ), 1 );\n}\n\nnamespace {\n    template < class T >\n    struct by_value : T {};\n}\n\nBOOST_AUTO_TEST_CASE( sum_by )\n{\n    BOOST_CHECK_EQUAL( ( bluetoe::details::sum_by< std::tuple<>, by_value >::value ), 0 );\n\n    BOOST_CHECK_EQUAL( (\n        bluetoe::details::sum_by<\n            std::tuple<\n                std::integral_constant< int, 4 >\n            >, by_value >::value ),\n        4 );\n\n    BOOST_CHECK_EQUAL( (\n        bluetoe::details::sum_by<\n            std::tuple<\n                std::integral_constant< int, 4 >,\n                std::integral_constant< int, 1 >\n            >, by_value >::value ),\n        5 );\n}\n\nBOOST_AUTO_TEST_CASE( find_if )\n{\n    BOOST_CHECK( (\n        std::is_same<\n            typename bluetoe::details::find_if< std::tuple< float, char, int >, is_int >::type,\n            int >::value\n    ) );\n\n    BOOST_CHECK( (\n        std::is_same<\n            typename bluetoe::details::find_if< std::tuple< int, float, char >, is_int >::type,\n            int >::value\n    ) );\n\n    BOOST_CHECK( (\n        std::is_same<\n            typename bluetoe::details::find_if< std::tuple< float, int, char >, is_int >::type,\n            int >::value\n    ) );\n\n    BOOST_CHECK( (\n        std::is_same<\n            typename bluetoe::details::find_if< std::tuple< int >, is_int >::type,\n            int >::value\n    ) );\n\n    BOOST_CHECK( (\n        std::is_same<\n            typename bluetoe::details::find_if< std::tuple<>, is_int >::type,\n            bluetoe::details::no_such_type >::value\n    ) );\n\n    BOOST_CHECK( (\n        std::is_same<\n            typename bluetoe::details::find_if< std::tuple< float, bool >, is_int >::type,\n            bluetoe::details::no_such_type >::value\n    ) );\n}\n\nBOOST_AUTO_TEST_CASE( last_from_pack )\n{\n    BOOST_CHECK( (\n        std::is_same<\n            typename bluetoe::details::last_from_pack< int >::type,\n            int >::value\n    ) );\n\n    BOOST_CHECK( (\n        std::is_same<\n            typename bluetoe::details::last_from_pack< float, int >::type,\n            int >::value\n    ) );\n\n}\n\nnamespace {\n    std::string ctor_order;\n\n    template < char C >\n    struct tag\n    {\n        tag()\n        {\n            ctor_order += C;\n        }\n    };\n\n    template < typename List >\n    static void test_derive_from( const std::string& expected )\n    {\n        ctor_order = \"\";\n        bluetoe::details::derive_from< List > instance;\n        static_cast< void >( instance );\n\n        BOOST_CHECK_EQUAL( ctor_order, expected );\n    }\n}\n\nBOOST_AUTO_TEST_CASE( derive_from )\n{\n    test_derive_from< std::tuple<> >( \"\" );\n    test_derive_from< std::tuple< tag<'A'> > >( \"A\" );\n    test_derive_from< std::tuple< tag<'A'>, tag<'B'> > >( \"AB\" );\n    test_derive_from< std::tuple< tag<'A'>, tag<'B'>, tag<'C'> > >( \"ABC\" );\n}\n\nnamespace {\n\n    template <\n        typename List,\n        typename E >\n    struct add_only_tags;\n\n    template <\n        char C,\n        typename ... Es >\n    struct add_only_tags< std::tuple< Es... >, tag< C > >\n    {\n        typedef std::tuple< tag< C >, Es... > type;\n    };\n\n    template < typename ... Ms, typename T >\n    struct add_only_tags< std::tuple< Ms... >, T >\n    {\n        typedef std::tuple< Ms... > type;\n    };\n}\n\nBOOST_AUTO_TEST_CASE( fold )\n{\n    BOOST_CHECK( (\n        std::is_same<\n            typename bluetoe::details::fold< std::tuple<>, add_only_tags >::type,\n            std::tuple<> >::value\n    ) );\n\n    BOOST_CHECK( (\n        std::is_same<\n            typename bluetoe::details::fold< std::tuple< int, tag<'A'>, float, tag<'B'> >, add_only_tags >::type,\n            std::tuple< tag<'A'>, tag<'B'> > >::value\n    ) );\n}\n\nBOOST_AUTO_TEST_CASE( transform_list )\n{\n    BOOST_CHECK( (\n        std::is_same<\n            typename bluetoe::details::transform_list< std::tuple<>, bluetoe::details::extract_meta_type >::type,\n            std::tuple<> >::value\n    ) );\n\n    BOOST_CHECK( (\n        std::is_same<\n            typename bluetoe::details::transform_list<\n                std::tuple< type1 >,\n                bluetoe::details::extract_meta_type\n            >::type,\n            std::tuple< meta1 > >::value\n    ) );\n\n    BOOST_CHECK( (\n        std::is_same<\n            typename bluetoe::details::transform_list<\n                std::tuple< type1, type2 >,\n                bluetoe::details::extract_meta_type\n            >::type,\n            std::tuple< meta1, meta2 > >::value\n    ) );\n\n    BOOST_CHECK( (\n        std::is_same<\n            typename bluetoe::details::transform_list<\n                std::tuple< type1, type2, type3 >,\n                bluetoe::details::extract_meta_type\n            >::type,\n            std::tuple< meta1, meta2, meta3 > >::value\n    ) );\n}\n\nBOOST_AUTO_TEST_CASE( index_of )\n{\n    BOOST_CHECK_EQUAL( 0, int( bluetoe::details::index_of< int, int >::value ) );\n    BOOST_CHECK_EQUAL( 0, int( bluetoe::details::index_of< int, std::tuple< int > >::value ) );\n\n    BOOST_CHECK_EQUAL( 0, int( bluetoe::details::index_of< int, int, float >::value ) );\n    BOOST_CHECK_EQUAL( 0, int( bluetoe::details::index_of< int, std::tuple< int, float > >::value ) );\n\n    BOOST_CHECK_EQUAL( 1, int( bluetoe::details::index_of< float, int, float >::value ) );\n    BOOST_CHECK_EQUAL( 1, int( bluetoe::details::index_of< float, std::tuple< int, float > >::value ) );\n\n    BOOST_CHECK_EQUAL( 2, int( bluetoe::details::index_of< bool, int, float, bool >::value ) );\n    BOOST_CHECK_EQUAL( 1, int( bluetoe::details::index_of< float, std::tuple< int, float, bool > >::value ) );\n\n    // not in list\n    BOOST_CHECK_EQUAL( 3, int( bluetoe::details::index_of< double, std::tuple< int, float, bool > >::value ) );\n\n    // not in empty list\n    BOOST_CHECK_EQUAL( 0, int( bluetoe::details::index_of< double, std::tuple<> >::value ) );\n    BOOST_CHECK_EQUAL( 0, int( bluetoe::details::index_of< double >::value ) );\n}\n\ntemplate < class A, class B >\nstruct sort_createria\n{\n    using type = typename bluetoe::details::select_type< A::value < B::value, std::true_type, std::false_type >::type;\n};\n\ntemplate < int I >\nusing int_ = std::integral_constant< int, I >;\n\nBOOST_AUTO_TEST_CASE( stable_sort_order )\n{\n    BOOST_CHECK( (\n        std::is_same<\n            typename bluetoe::details::stable_sort< sort_createria >::type,\n            std::tuple<> >::value\n    ) );\n\n    BOOST_CHECK( (\n        std::is_same<\n            typename bluetoe::details::stable_sort< sort_createria, std::tuple<> >::type,\n            std::tuple<> >::value\n    ) );\n\n\n    BOOST_CHECK( (\n        std::is_same<\n            typename bluetoe::details::stable_sort< sort_createria, int_< 1 > >::type,\n            std::tuple< int_< 1 > > >::value\n    ) );\n\n    BOOST_CHECK( (\n        std::is_same<\n            typename bluetoe::details::stable_sort< sort_createria, int_< 1 >, int_< 2 > >::type,\n            std::tuple< int_< 1 >, int_< 2 > > >::value\n    ) );\n\n    BOOST_CHECK( (\n        std::is_same<\n            typename bluetoe::details::stable_sort< sort_createria, int_< 2 >, int_< 1 > >::type,\n            std::tuple< int_< 1 >, int_< 2 > > >::value\n    ) );\n\n    BOOST_CHECK( (\n        std::is_same<\n            typename bluetoe::details::stable_sort< sort_createria, int_< 1 >, int_< 2 >, int_< 3 > >::type,\n            std::tuple< int_< 1 >, int_< 2 >, int_< 3 > > >::value\n    ) );\n\n    BOOST_CHECK( (\n        std::is_same<\n            typename bluetoe::details::stable_sort< sort_createria, int_< 2 >, int_< 1 >, int_< 3 > >::type,\n            std::tuple< int_< 1 >, int_< 2 >, int_< 3 > > >::value\n    ) );\n\n    BOOST_CHECK( (\n        std::is_same<\n            typename bluetoe::details::stable_sort< sort_createria, int_< 3 >, int_< 2 >, int_< 1 > >::type,\n            std::tuple< int_< 1 >, int_< 2 >, int_< 3 > > >::value\n    ) );\n\n    BOOST_CHECK( (\n        std::is_same<\n            typename bluetoe::details::stable_sort< sort_createria, int_< 1 >, int_< 3 >, int_< 2 > >::type,\n            std::tuple< int_< 1 >, int_< 2 >, int_< 3 > > >::value\n    ) );\n\n    BOOST_CHECK( (\n        std::is_same<\n            typename bluetoe::details::stable_sort< sort_createria, int_< 1 >, int_< 3 >, int_< 5 >, int_< 2 >, int_< 1 > >::type,\n            std::tuple< int_< 1 >, int_< 1 >, int_< 2 >, int_< 3 >, int_< 5 > > >::value\n    ) );\n}\n\ntemplate < char A, char B >\nstruct item {\n    static const char key = A;\n};\n\ntemplate < class first, class second >\nstruct order_item\n{\n    using type = typename bluetoe::details::select_type<\n        first::key < second::key,\n        std::true_type,\n        std::false_type >::type;\n};\n\nBOOST_AUTO_TEST_CASE( stable_sort_stability )\n{\n    BOOST_CHECK( (\n        std::is_same<\n            typename bluetoe::details::stable_sort< order_item, item< 'A', 'A' > >::type,\n            std::tuple< item< 'A', 'A' > > >::value\n    ) );\n\n    BOOST_CHECK( (\n        std::is_same<\n            typename bluetoe::details::stable_sort< order_item, item< 'A', 'A' >, item< 'A', 'B' > >::type,\n            std::tuple< item< 'A', 'A' >, item< 'A', 'B' > > >::value\n    ) );\n\n\n    BOOST_CHECK( (\n        std::is_same<\n            typename bluetoe::details::stable_sort< order_item, item< 'B', 'A' >, item< 'A', 'B' >, item< 'B', 'B' >, item< 'A', 'C' > >::type,\n            std::tuple< item< 'A', 'B' >, item< 'A', 'C' >, item< 'B', 'A' >, item< 'B', 'B' > > >::value\n    ) );\n}\n\nBOOST_AUTO_TEST_CASE( last_type )\n{\n    BOOST_CHECK( (\n        std::is_same<\n            typename bluetoe::details::last_type< std::tuple<> >::type,\n            bluetoe::details::no_such_type >::value\n    ) );\n\n    BOOST_CHECK( (\n        std::is_same<\n            typename bluetoe::details::last_type< std::tuple<>, char >::type,\n            char >::value\n    ) );\n\n    BOOST_CHECK( (\n        std::is_same<\n            typename bluetoe::details::last_type< std::tuple< char > >::type,\n            char >::value\n    ) );\n\n    BOOST_CHECK( (\n        std::is_same<\n            typename bluetoe::details::last_type< std::tuple< char, double > >::type,\n            double >::value\n    ) );\n}\n\nBOOST_AUTO_TEST_CASE( map_find )\n{\n    BOOST_CHECK( (\n        std::is_same<\n            typename bluetoe::details::map_find< std::tuple<>, int >::type,\n            bluetoe::details::no_such_type\n        >::value\n    ) );\n\n    BOOST_CHECK( (\n        std::is_same<\n            typename bluetoe::details::map_find< std::tuple<>, int, float >::type,\n            float\n        >::value\n    ) );\n\n    BOOST_CHECK( (\n        std::is_same<\n            typename bluetoe::details::map_find<\n                std::tuple<\n                    bluetoe::details::pair< int, char >\n                >, int >::type,\n            char\n        >::value\n    ) );\n\n    BOOST_CHECK( (\n        std::is_same<\n            typename bluetoe::details::map_find<\n                std::tuple<\n                    bluetoe::details::pair< int, char >, bluetoe::details::pair< float, bool >\n                >, float >::type,\n            bool\n        >::value\n    ) );\n\n    BOOST_CHECK( (\n        std::is_same<\n            typename bluetoe::details::map_find<\n                std::tuple<\n                    bluetoe::details::pair< int, char >, bluetoe::details::pair< float, bool >\n                >, double >::type,\n            bluetoe::details::no_such_type\n        >::value\n    ) );\n}\n\nBOOST_AUTO_TEST_CASE( map_erase )\n{\n    BOOST_CHECK( (\n        std::is_same<\n            typename bluetoe::details::map_erase< std::tuple<>, int >::type,\n            std::tuple<>\n        >::value\n    ) );\n\n    BOOST_CHECK( (\n        std::is_same<\n            typename bluetoe::details::map_erase< std::tuple< bluetoe::details::pair< int, char > >, int >::type,\n            std::tuple<>\n        >::value\n    ) );\n\n    BOOST_CHECK( (\n        std::is_same<\n            typename bluetoe::details::map_erase< std::tuple< bluetoe::details::pair< int, char > >, bool >::type,\n            std::tuple< bluetoe::details::pair< int, char > >\n        >::value\n    ) );\n\n    BOOST_CHECK( (\n        std::is_same<\n            typename bluetoe::details::map_erase<\n                std::tuple<\n                    bluetoe::details::pair< int, char >,\n                    bluetoe::details::pair< bool, char >,\n                    bluetoe::details::pair< float, char >\n                >, bool >::type,\n            std::tuple< bluetoe::details::pair< int, char >, bluetoe::details::pair< float, char > >\n        >::value\n    ) );\n}\n\nBOOST_AUTO_TEST_CASE( map_insert )\n{\n    BOOST_CHECK( (\n        std::is_same<\n            typename bluetoe::details::map_insert< std::tuple<>, int, char >::type,\n            std::tuple< bluetoe::details::pair< int, char > >\n        >::value\n    ) );\n\n    BOOST_CHECK( (\n        std::is_same<\n            typename bluetoe::details::map_insert< std::tuple< bluetoe::details::pair< int, char > >, int, char >::type,\n            std::tuple< bluetoe::details::pair< int, char > >\n        >::value\n    ) );\n\n    BOOST_CHECK( (\n        std::is_same<\n            typename bluetoe::details::map_insert< std::tuple< bluetoe::details::pair< int, bool > >, int, char >::type,\n            std::tuple< bluetoe::details::pair< int, char > >\n        >::value\n    ) );\n}\n"
  },
  {
    "path": "tests/read_write_handler_tests.cpp",
    "content": "#include <iostream>\n#include <iterator>\n\n#include <bluetoe/characteristic_value.hpp>\n#include <bluetoe/characteristic.hpp>\n#include <bluetoe/service.hpp>\n#include <bluetoe/server.hpp>\n\n#define BOOST_TEST_MODULE\n#include <boost/test/included/unit_test.hpp>\n\n#include <boost/mpl/list.hpp>\n#include <boost/mpl/insert_range.hpp>\n\n#include \"hexdump.hpp\"\n#include \"test_attribute_access.hpp\"\n#include \"test_tuple.hpp\"\n\nstatic const std::uint8_t test_read_value[] = { 0x01, 0x02, 0x03, 0x04, 0x05 };\n\nusing cccd_indices = std::tuple<>;\nusing suuid = bluetoe::service_uuid16< 0x4711 >;\nusing srv   = bluetoe::server<>;\n\nstd::uint8_t read_blob_test_value_handler( std::size_t offset, std::size_t read_size, std::uint8_t* out_buffer, std::size_t& out_size )\n{\n    if ( offset > sizeof( test_read_value ) )\n        return bluetoe::error_codes::invalid_offset;\n\n    out_size = std::min( sizeof( test_read_value ) - offset, read_size );\n    std::copy( &test_read_value[ offset ], &test_read_value[ offset + out_size ], out_buffer );\n\n    return bluetoe::error_codes::success;\n}\n\nstd::uint8_t read_test_value_handler( std::size_t read_size, std::uint8_t* out_buffer, std::size_t& out_size )\n{\n    return read_blob_test_value_handler( 0, read_size, out_buffer, out_size );\n}\n\nstatic std::uint8_t test_write_value[ 6 ];\n\nstd::uint8_t write_blob_test_value_handler( std::size_t offset, std::size_t write_size, const std::uint8_t* value )\n{\n    if ( offset > sizeof( test_write_value ) )\n        return bluetoe::error_codes::invalid_offset;\n\n    const std::size_t copy_size = std::min( sizeof( test_write_value ) - offset, write_size );\n    std::copy( value, value + copy_size, std::begin( test_write_value ) + offset );\n\n    return bluetoe::error_codes::success;\n}\n\nstd::uint8_t write_test_value_handler( std::size_t write_size, const std::uint8_t* value )\n{\n    return write_blob_test_value_handler( 0, write_size, value );\n}\n\nstruct read_blob_handler_class {\n\n    std::uint8_t read_handler( std::size_t offset, std::size_t read_size, std::uint8_t* out_buffer, std::size_t& out_size )\n    {\n        return read_blob_test_value_handler( offset, read_size, out_buffer, out_size );\n    }\n\n    std::uint8_t read_handler_c( std::size_t offset, std::size_t read_size, std::uint8_t* out_buffer, std::size_t& out_size ) const\n    {\n        return read_blob_test_value_handler( offset, read_size, out_buffer, out_size );\n    }\n\n    std::uint8_t read_handler_v( std::size_t offset, std::size_t read_size, std::uint8_t* out_buffer, std::size_t& out_size ) volatile\n    {\n        return read_blob_test_value_handler( offset, read_size, out_buffer, out_size );\n    }\n\n    std::uint8_t read_handler_cv( std::size_t offset, std::size_t read_size, std::uint8_t* out_buffer, std::size_t& out_size ) const volatile\n    {\n        return read_blob_test_value_handler( offset, read_size, out_buffer, out_size );\n    }\n\n} read_blob_handler_instance;\n\nstruct read_handler_class {\n\n    std::uint8_t read_handler( std::size_t read_size, std::uint8_t* out_buffer, std::size_t& out_size )\n    {\n        return read_test_value_handler( read_size, out_buffer, out_size );\n    }\n\n    std::uint8_t read_handler_c( std::size_t read_size, std::uint8_t* out_buffer, std::size_t& out_size ) const\n    {\n        return read_test_value_handler( read_size, out_buffer, out_size );\n    }\n\n    std::uint8_t read_handler_v( std::size_t read_size, std::uint8_t* out_buffer, std::size_t& out_size ) volatile\n    {\n        return read_test_value_handler( read_size, out_buffer, out_size );\n    }\n\n    std::uint8_t read_handler_cv( std::size_t read_size, std::uint8_t* out_buffer, std::size_t& out_size ) const volatile\n    {\n        return read_test_value_handler( read_size, out_buffer, out_size );\n    }\n\n} read_handler_instance;\n\nstruct write_blob_handler_class {\n    std::uint8_t write_handler( std::size_t offset, std::size_t write_size, const std::uint8_t* value )\n    {\n        return write_blob_test_value_handler( offset, write_size, value );\n    }\n\n    std::uint8_t write_handler_c( std::size_t offset, std::size_t write_size, const std::uint8_t* value ) const\n    {\n        return write_blob_test_value_handler( offset, write_size, value );\n    }\n\n    std::uint8_t write_handler_v( std::size_t offset, std::size_t write_size, const std::uint8_t* value ) volatile\n    {\n        return write_blob_test_value_handler( offset, write_size, value );\n    }\n\n    std::uint8_t write_handler_cv( std::size_t offset, std::size_t write_size, const std::uint8_t* value ) const volatile\n    {\n        return write_blob_test_value_handler( offset, write_size, value );\n    }\n\n} write_blob_handler_instance;\n\nstruct write_handler_class {\n    std::uint8_t write_handler( std::size_t write_size, const std::uint8_t* value )\n    {\n        return write_test_value_handler( write_size, value );\n    }\n\n    std::uint8_t write_handler_c( std::size_t write_size, const std::uint8_t* value ) const\n    {\n        return write_test_value_handler( write_size, value );\n    }\n\n    std::uint8_t write_handler_v( std::size_t write_size, const std::uint8_t* value ) volatile\n    {\n        return write_test_value_handler( write_size, value );\n    }\n\n    std::uint8_t write_handler_cv( std::size_t write_size, const std::uint8_t* value ) const volatile\n    {\n        return write_test_value_handler( write_size, value );\n    }\n\n} write_handler_instance;\n\ntypedef boost::mpl::list<\n        bluetoe::characteristic<\n            bluetoe::characteristic_uuid16< 0x1212 >,\n            bluetoe::free_read_blob_handler< &read_blob_test_value_handler >\n        >,\n        bluetoe::characteristic<\n            bluetoe::characteristic_uuid16< 0x1212 >,\n            bluetoe::read_blob_handler< read_blob_handler_class, read_blob_handler_instance, &read_blob_handler_class::read_handler >\n        >,\n        bluetoe::characteristic<\n            bluetoe::characteristic_uuid16< 0x1212 >,\n            bluetoe::read_blob_handler_c< read_blob_handler_class, read_blob_handler_instance, &read_blob_handler_class::read_handler_c >\n        >,\n        bluetoe::characteristic<\n            bluetoe::characteristic_uuid16< 0x1212 >,\n            bluetoe::read_blob_handler_v< read_blob_handler_class, read_blob_handler_instance, &read_blob_handler_class::read_handler_v >\n        >,\n        bluetoe::characteristic<\n            bluetoe::characteristic_uuid16< 0x1212 >,\n            bluetoe::read_blob_handler_cv< read_blob_handler_class, read_blob_handler_instance, &read_blob_handler_class::read_handler_cv >\n        >\n    > read_blob_handler_tests;\n\ntypedef boost::mpl::list<\n        bluetoe::characteristic<\n            bluetoe::characteristic_uuid16< 0x1212 >,\n            bluetoe::free_read_blob_handler< &read_blob_test_value_handler >,\n            bluetoe::free_write_blob_handler< &write_blob_test_value_handler >\n        >,\n        bluetoe::characteristic<\n            bluetoe::characteristic_uuid16< 0x1212 >,\n            bluetoe::read_blob_handler_v< read_blob_handler_class, read_blob_handler_instance, &read_blob_handler_class::read_handler_v >,\n            bluetoe::write_blob_handler< write_blob_handler_class, write_blob_handler_instance, &write_blob_handler_class::write_handler >\n        >\n    > read_write_blob_handler_tests;\n\ntypedef boost::mpl::list<\n        bluetoe::characteristic<\n            bluetoe::characteristic_uuid16< 0x1212 >,\n            bluetoe::free_read_handler< &read_test_value_handler >\n        >,\n        bluetoe::characteristic<\n            bluetoe::characteristic_uuid16< 0x1212 >,\n            bluetoe::read_handler< read_handler_class, read_handler_instance, &read_handler_class::read_handler >\n        >,\n        bluetoe::characteristic<\n            bluetoe::characteristic_uuid16< 0x1212 >,\n            bluetoe::read_handler_c< read_handler_class, read_handler_instance, &read_handler_class::read_handler_c >\n        >,\n        bluetoe::characteristic<\n            bluetoe::characteristic_uuid16< 0x1212 >,\n            bluetoe::read_handler_v< read_handler_class, read_handler_instance, &read_handler_class::read_handler_v >\n        >,\n        bluetoe::characteristic<\n            bluetoe::characteristic_uuid16< 0x1212 >,\n            bluetoe::read_handler_cv< read_handler_class, read_handler_instance, &read_handler_class::read_handler_cv >\n        >\n    > read_handler_tests;\n\ntypedef boost::mpl::list<\n        bluetoe::characteristic<\n            bluetoe::characteristic_uuid16< 0x1212 >,\n            bluetoe::free_write_blob_handler< &write_blob_test_value_handler >\n        >,\n        bluetoe::characteristic<\n            bluetoe::characteristic_uuid16< 0x1212 >,\n            bluetoe::write_blob_handler< write_blob_handler_class, write_blob_handler_instance, &write_blob_handler_class::write_handler >\n        >,\n        bluetoe::characteristic<\n            bluetoe::characteristic_uuid16< 0x1212 >,\n            bluetoe::write_blob_handler_c< write_blob_handler_class, write_blob_handler_instance, &write_blob_handler_class::write_handler_c >\n        >,\n        bluetoe::characteristic<\n            bluetoe::characteristic_uuid16< 0x1212 >,\n            bluetoe::write_blob_handler_v< write_blob_handler_class, write_blob_handler_instance, &write_blob_handler_class::write_handler_v >\n        >,\n        bluetoe::characteristic<\n            bluetoe::characteristic_uuid16< 0x1212 >,\n            bluetoe::write_blob_handler_cv< write_blob_handler_class, write_blob_handler_instance, &write_blob_handler_class::write_handler_cv >\n        >\n    > write_blob_handler_tests;\n\ntypedef boost::mpl::list<\n        bluetoe::characteristic<\n            bluetoe::characteristic_uuid16< 0x1212 >,\n            bluetoe::free_raw_write_handler< &write_test_value_handler >\n        >,\n        bluetoe::characteristic<\n            bluetoe::characteristic_uuid16< 0x1212 >,\n            bluetoe::write_handler< write_handler_class, write_handler_instance, &write_handler_class::write_handler >\n        >,\n        bluetoe::characteristic<\n            bluetoe::characteristic_uuid16< 0x1212 >,\n            bluetoe::write_handler_c< write_handler_class, write_handler_instance, &write_handler_class::write_handler_c >\n        >,\n        bluetoe::characteristic<\n            bluetoe::characteristic_uuid16< 0x1212 >,\n            bluetoe::write_handler_v< write_handler_class, write_handler_instance, &write_handler_class::write_handler_v >\n        >,\n        bluetoe::characteristic<\n            bluetoe::characteristic_uuid16< 0x1212 >,\n            bluetoe::write_handler_cv< write_handler_class, write_handler_instance, &write_handler_class::write_handler_cv >\n        >\n    > write_handler_tests;\n\ntypedef typename boost::mpl::insert_range<\n    read_blob_handler_tests,\n    typename boost::mpl::begin< read_blob_handler_tests >::type,\n    read_write_blob_handler_tests >::type all_read_blob_handler_tests;\n\ntypedef typename boost::mpl::insert_range<\n    all_read_blob_handler_tests,\n    typename boost::mpl::begin< all_read_blob_handler_tests >::type,\n    read_handler_tests >::type all_read_handler_tests;\n\ntypedef typename boost::mpl::insert_range<\n    read_blob_handler_tests,\n    typename boost::mpl::begin< read_blob_handler_tests >::type,\n    read_handler_tests >::type all_read_only_handler_tests;\n\ntypedef typename boost::mpl::insert_range<\n    write_blob_handler_tests,\n    typename boost::mpl::begin< write_blob_handler_tests >::type,\n    read_write_blob_handler_tests >::type all_write_blob_handler_tests;\n\ntypedef typename boost::mpl::insert_range<\n    all_write_blob_handler_tests,\n    typename boost::mpl::begin< all_write_blob_handler_tests >::type,\n    write_handler_tests >::type all_write_handler_tests;\n\ntypedef typename boost::mpl::insert_range<\n    write_blob_handler_tests,\n    typename boost::mpl::begin< write_blob_handler_tests >::type,\n    write_handler_tests >::type all_write_only_handler_tests;\n\nBOOST_AUTO_TEST_CASE_TEMPLATE( test_read_blob_handlers, Attribute, all_read_handler_tests )\n{\n    const auto attr = Attribute::template attribute_at< cccd_indices, 0, bluetoe::service< suuid >, srv >( 1 );\n    std::uint8_t    buffer[ 100 ];\n\n    auto access = bluetoe::details::attribute_access_arguments::read( buffer, 0 );\n    BOOST_CHECK( attr.access( access, 1 ) == bluetoe::details::attribute_access_result::success );\n\n    BOOST_CHECK_EQUAL( access.buffer_size, sizeof( test_read_value ) );\n    BOOST_CHECK_EQUAL_COLLECTIONS( std::begin( test_read_value ), std::end( test_read_value ), &buffer[ 0 ], &buffer[ access.buffer_size ] );\n}\n\nBOOST_AUTO_TEST_CASE_TEMPLATE( test_no_write_access_read_blob_handlers, Attribute, all_read_only_handler_tests )\n{\n    const auto attr = Attribute::template attribute_at< cccd_indices, 0, bluetoe::service< suuid >, srv >( 1 );\n\n    auto access = bluetoe::details::attribute_access_arguments::write( test_read_value );\n    BOOST_CHECK( attr.access( access, 1 ) == bluetoe::details::attribute_access_result::write_not_permitted );\n}\n\nBOOST_AUTO_TEST_CASE_TEMPLATE( test_read_blob_with_offset, Attribute, read_blob_handler_tests )\n{\n    const auto attr = Attribute::template attribute_at< cccd_indices, 0, bluetoe::service< suuid >, srv >( 1 );\n    std::uint8_t    buffer[ 100 ];\n\n    auto access = bluetoe::details::attribute_access_arguments::read( buffer, 2 );\n    BOOST_CHECK( attr.access( access, 1 ) == bluetoe::details::attribute_access_result::success );\n\n    BOOST_CHECK_EQUAL( access.buffer_size, sizeof( test_read_value ) - 2 );\n    BOOST_CHECK_EQUAL_COLLECTIONS( std::begin( test_read_value ) + 2, std::end( test_read_value ), &buffer[ 0 ], &buffer[ access.buffer_size ] );\n}\n\nBOOST_AUTO_TEST_CASE_TEMPLATE( test_read_with_offset, Attribute, read_handler_tests )\n{\n    const auto attr = Attribute::template attribute_at< cccd_indices, 0, bluetoe::service< suuid >, srv >( 1 );\n    std::uint8_t    buffer[ 100 ];\n\n    auto access = bluetoe::details::attribute_access_arguments::read( buffer, 2 );\n    BOOST_CHECK( attr.access( access, 1 ) == bluetoe::details::attribute_access_result::attribute_not_long );\n}\n\nBOOST_AUTO_TEST_CASE_TEMPLATE( test_read_handler_characteristic_declaration_uuid, Attribute, read_handler_tests )\n{\n    const auto attr = Attribute::template attribute_at< cccd_indices, 0, bluetoe::service< suuid >, srv >( 0 );\n\n    BOOST_CHECK_EQUAL( attr.uuid, 0x2803 );\n}\n\nBOOST_AUTO_TEST_CASE_TEMPLATE( test_read_handler_characteristic_declaration_value, Attribute, read_handler_tests )\n{\n    access_attributes< Attribute >().compare_characteristic( { 0x02, 0x02, 0x00, 0x12, 0x12 }, 0x2803 );\n}\n\nBOOST_AUTO_TEST_CASE( test_read_handler_characteristic_declaration_value_for_notifyable )\n{\n    using read_handler_with_notification = bluetoe::characteristic<\n        bluetoe::characteristic_uuid16< 0x1215 >,\n        bluetoe::notify,\n        bluetoe::free_read_handler< &read_test_value_handler >\n    >;\n\n    access_attributes< read_handler_with_notification >().compare_characteristic( { 0x12, 0x02, 0x00, 0x15, 0x12 }, 0x2803 );\n}\n\nBOOST_AUTO_TEST_CASE( test_read_handler_characteristic_declaration_value_for_indication )\n{\n    using read_handler_with_notification = bluetoe::characteristic<\n        bluetoe::characteristic_uuid16< 0x1215 >,\n        bluetoe::indicate,\n        bluetoe::free_read_handler< &read_test_value_handler >\n    >;\n\n    access_attributes< read_handler_with_notification >().compare_characteristic( { 0x22, 0x02, 0x00, 0x15, 0x12 }, 0x2803 );\n}\n\nBOOST_AUTO_TEST_CASE( test_read_handler_characteristic_declaration_value_for_indication_and_notification )\n{\n    using read_handler_with_notification = bluetoe::characteristic<\n        bluetoe::characteristic_uuid16< 0x1215 >,\n        bluetoe::notify,\n        bluetoe::indicate,\n        bluetoe::free_read_handler< &read_test_value_handler >\n    >;\n\n    access_attributes< read_handler_with_notification >().compare_characteristic( { 0x32, 0x02, 0x00, 0x15, 0x12 }, 0x2803 );\n}\n\nBOOST_AUTO_TEST_CASE( test_not_readable_read_handler_characteristic_declaration_value_for_notification )\n{\n    using read_handler_with_notification = bluetoe::characteristic<\n        bluetoe::characteristic_uuid16< 0x1215 >,\n        bluetoe::notify,\n        bluetoe::no_read_access,\n        bluetoe::free_read_handler< &read_test_value_handler >\n    >;\n\n    access_attributes< read_handler_with_notification >().compare_characteristic( { 0x10, 0x02, 0x00, 0x15, 0x12 }, 0x2803 );\n}\n\nstruct reset_test_write_value {\n    reset_test_write_value()\n    {\n        std::fill( std::begin( test_write_value ), std::end( test_write_value ), 0 );\n    }\n};\n\nBOOST_FIXTURE_TEST_SUITE( test_write_handlers, reset_test_write_value )\n\nBOOST_AUTO_TEST_CASE_TEMPLATE( test_write_handlers, Attribute, all_write_handler_tests )\n{\n    static const std::uint8_t fixture[] = { 0xaa, 0xbb, 0xcc };\n    const auto attr = Attribute::template attribute_at< cccd_indices, 0, bluetoe::service< suuid >, srv >( 1 );\n\n    auto access = bluetoe::details::attribute_access_arguments::write( fixture );\n    BOOST_CHECK( attr.access( access, 1 ) == bluetoe::details::attribute_access_result::success );\n    BOOST_CHECK_EQUAL_COLLECTIONS( std::begin( fixture ), std::end( fixture ), &test_write_value[ 0 ], &test_write_value[ sizeof( fixture ) ] );\n}\n\nBOOST_AUTO_TEST_CASE_TEMPLATE( test_no_read_access_to_write_handler, Attribute, all_write_only_handler_tests )\n{\n    const auto attr = Attribute::template attribute_at< cccd_indices, 0, bluetoe::service< suuid >, srv >( 1 );\n    std::uint8_t    buffer[ 100 ];\n\n    auto access = bluetoe::details::attribute_access_arguments::read( buffer, 0 );\n    BOOST_CHECK( attr.access( access, 1 ) == bluetoe::details::attribute_access_result::read_not_permitted );\n}\n\nBOOST_AUTO_TEST_CASE_TEMPLATE( test_write_blob_with_offset, Attribute, all_write_blob_handler_tests )\n{\n    static const std::uint8_t fixture[] = { 0xaa, 0xbb, 0xcc };\n    static const std::uint8_t expected_value[] = { 0x00, 0x00, 0xaa, 0xbb, 0xcc };\n\n    const auto attr = Attribute::template attribute_at< cccd_indices, 0, bluetoe::service< suuid >, srv >( 1 );\n\n    auto access = bluetoe::details::attribute_access_arguments::write( fixture, 2 );\n\n    BOOST_CHECK( attr.access( access, 1 ) == bluetoe::details::attribute_access_result::success );\n    BOOST_CHECK_EQUAL_COLLECTIONS( std::begin( expected_value ), std::end( expected_value ), &test_write_value[ 0 ], &test_write_value[ sizeof( expected_value ) ] );\n}\n\nBOOST_AUTO_TEST_CASE_TEMPLATE( test_write_with_offset, Attribute, write_handler_tests )\n{\n    static const std::uint8_t fixture[] = { 0xaa, 0xbb, 0xcc };\n\n    const auto attr = Attribute::template attribute_at< cccd_indices, 0, bluetoe::service< suuid >, srv >( 1 );\n    auto access = bluetoe::details::attribute_access_arguments::write( fixture, 2 );\n\n    BOOST_CHECK( attr.access( access, 1 ) == bluetoe::details::attribute_access_result::attribute_not_long );\n}\n\nBOOST_AUTO_TEST_CASE( test_write_handler_characteristic_declaration_value )\n{\n    using write_handler = bluetoe::characteristic<\n        bluetoe::characteristic_uuid16< 0x1215 >,\n        bluetoe::free_raw_write_handler< &write_test_value_handler >\n    >;\n\n    access_attributes< write_handler >().compare_characteristic( { 0x08, 0x02, 0x00, 0x15, 0x12 }, 0x2803 );\n}\n\nBOOST_AUTO_TEST_CASE( test_write_handler_characteristic_declaration_value_for_notifyable )\n{\n    using write_handler = bluetoe::characteristic<\n        bluetoe::characteristic_uuid16< 0x1215 >,\n        bluetoe::notify,\n        bluetoe::free_read_handler< &read_test_value_handler >,\n        bluetoe::free_raw_write_handler< &write_test_value_handler >\n    >;\n\n    access_attributes< write_handler >().compare_characteristic( { 0x1a, 0x02, 0x00, 0x15, 0x12 }, 0x2803 );\n}\n\nBOOST_AUTO_TEST_CASE( test_write_handler_characteristic_declaration_value_for_indication )\n{\n    using write_handler = bluetoe::characteristic<\n        bluetoe::characteristic_uuid16< 0x1215 >,\n        bluetoe::indicate,\n        bluetoe::free_raw_write_handler< &write_test_value_handler >,\n        bluetoe::free_read_handler< &read_test_value_handler >\n    >;\n\n    access_attributes< write_handler >().compare_characteristic( { 0x2a, 0x02, 0x00, 0x15, 0x12 }, 0x2803 );\n}\n\nBOOST_AUTO_TEST_CASE( test_write_handler_characteristic_declaration_value_for_indication_and_notification )\n{\n    using write_handler = bluetoe::characteristic<\n        bluetoe::characteristic_uuid16< 0x1215 >,\n        bluetoe::notify,\n        bluetoe::indicate,\n        bluetoe::free_raw_write_handler< &write_test_value_handler >,\n        bluetoe::free_read_handler< &read_test_value_handler >\n    >;\n\n    access_attributes< write_handler >().compare_characteristic( { 0x3a, 0x02, 0x00, 0x15, 0x12 }, 0x2803 );\n}\n\nBOOST_AUTO_TEST_CASE( test_not_readable_write_handler_characteristic_declaration_value_for_notification )\n{\n    using write_handler = bluetoe::characteristic<\n        bluetoe::characteristic_uuid16< 0x1215 >,\n        bluetoe::notify,\n        bluetoe::indicate,\n        bluetoe::no_read_access,\n        bluetoe::free_read_handler< &read_test_value_handler >,\n        bluetoe::free_raw_write_handler< &write_test_value_handler >\n    >;\n\n    access_attributes< write_handler >().compare_characteristic( { 0x38, 0x02, 0x00, 0x15, 0x12 }, 0x2803 );\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE( mixin_handlers )\n\nstruct write_mixin\n{\n    write_mixin()\n        : write_size( 0 )\n        , value( nullptr )\n    {\n    }\n\n    std::uint8_t write_handler( std::size_t w, const std::uint8_t* v )\n    {\n        write_size = w;\n        value      = v;\n\n        return 42;\n    }\n\n    std::size_t         write_size;\n    const std::uint8_t* value;\n};\n\nusing writeable_char = bluetoe::characteristic<\n    bluetoe::characteristic_uuid16< 0x1234 >,\n    bluetoe::mixin_write_handler< write_mixin, &write_mixin::write_handler >\n>;\n\nusing write_mixin_service =\n    bluetoe::service<\n        bluetoe::service_uuid< 0xF8C90690, 0x3BFE, 0x4303, 0x8CE9, 0xC30C024987C8 >,\n        writeable_char,\n        bluetoe::mixin< write_mixin >\n    >;\nusing write_mixin_server = bluetoe::server< write_mixin_service >;\n\nBOOST_FIXTURE_TEST_CASE( write_to_mixin, write_mixin_server )\n{\n    static const std::uint8_t fixture[] = { 0xaa, 0xbb, 0xcc };\n\n    const auto attr = writeable_char::attribute_at< cccd_indices, 0, write_mixin_service, write_mixin_server >( 1 );\n    auto access = bluetoe::details::attribute_access_arguments::write( fixture );\n    access.server = static_cast< write_mixin_server* >( this );\n\n    BOOST_CHECK_EQUAL( static_cast< std::int_fast16_t >( attr.access( access, 0 ) ), 42 );\n    BOOST_CHECK_EQUAL( write_size, sizeof(fixture) );\n    BOOST_CHECK( value == &fixture[ 0 ] );\n}\n\nstruct read_mixin\n{\n    std::uint8_t read_handler( std::size_t, std::uint8_t* out_buffer, std::size_t& out_size )\n    {\n        static constexpr std::uint8_t output[] = { 0x01, 0x02, 0x03, 0x04, 0x05 };\n\n        std::copy( std::begin( output ), std::end( output ), out_buffer );\n        out_size = std::distance( std::begin( output ), std::end( output ) );\n\n        return 33;\n    }\n};\n\nusing readable_char = bluetoe::characteristic<\n    bluetoe::characteristic_uuid16< 0x1234 >,\n    bluetoe::mixin_read_handler< read_mixin, &read_mixin::read_handler >\n>;\n\nusing read_mixin_service = bluetoe::service<\n    bluetoe::service_uuid< 0xF8C90690, 0x3BFE, 0x4303, 0x8CE9, 0xC30C024987C8 >,\n    readable_char,\n    bluetoe::mixin< read_mixin >\n>;\n\nusing read_mixin_server = bluetoe::server< read_mixin_service >;\n\nBOOST_FIXTURE_TEST_CASE( read_from_mixin, read_mixin_server )\n{\n    std::uint8_t buffer[ 100 ];\n\n    const auto attr = readable_char::attribute_at< cccd_indices, 0, read_mixin_service, read_mixin_server >( 1 );\n    auto read       = bluetoe::details::attribute_access_arguments::read( std::begin( buffer ), std::end( buffer ), 0,\n                        bluetoe::details::client_characteristic_configuration(),\n                        bluetoe::connection_security_attributes(),\n                        static_cast< read_mixin_server* >( this ) );\n\n    static constexpr std::uint8_t expected[] = { 0x01, 0x02, 0x03, 0x04, 0x05 };\n\n    BOOST_CHECK_EQUAL( static_cast< std::int_fast16_t >( attr.access( read, 0 ) ), 33 );\n    BOOST_CHECK_EQUAL( read.buffer_size, sizeof(expected) );\n    BOOST_CHECK_EQUAL_COLLECTIONS( &buffer[ 0 ], &buffer[ read.buffer_size ], std::begin( expected ), std::end( expected ) );\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE( free_write_handler_bool )\n\n    bool written_bool = false;\n    bool free_write_bool_handler_called = false;\n    std::uint8_t free_write_result = 0;\n\n    std::uint8_t free_write_bool_handler( bool b )\n    {\n        BOOST_REQUIRE( !free_write_bool_handler_called );\n\n        written_bool = b;\n        free_write_bool_handler_called = true;\n        return free_write_result;\n    }\n\n    typedef bluetoe::characteristic<\n        bluetoe::characteristic_uuid16< 0x1245 >,\n        bluetoe::free_write_handler< bool, &free_write_bool_handler >\n    > free_write_bool_char;\n\n    template < class Attr >\n    struct reset_bool : access_attributes< Attr >\n    {\n        reset_bool()\n        {\n            written_bool                    = false;\n            free_write_bool_handler_called  = false;\n            free_write_result               = 0;\n        }\n    };\n\n    BOOST_FIXTURE_TEST_CASE( write_bool_with_offset, reset_bool< free_write_bool_char > )\n    {\n        BOOST_CHECK( write_attribute_at( { 0x00, 0x00, 0x00, 0x00 }, 1, 1 ) == bluetoe::details::attribute_access_result::attribute_not_long );\n        BOOST_CHECK( !free_write_bool_handler_called );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( write_bool_false, reset_bool< free_write_bool_char > )\n    {\n        BOOST_CHECK( write_attribute_at( { 0x00 } ) == bluetoe::details::attribute_access_result::success );\n        BOOST_CHECK( written_bool == false );\n        BOOST_CHECK( free_write_bool_handler_called );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( write_bool_true, reset_bool< free_write_bool_char > )\n    {\n        BOOST_CHECK( write_attribute_at( { 0x01 } ) == bluetoe::details::attribute_access_result::success );\n        BOOST_CHECK( written_bool == true );\n        BOOST_CHECK( free_write_bool_handler_called );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( write_bool_invalid, reset_bool< free_write_bool_char > )\n    {\n        BOOST_CHECK( static_cast< bluetoe::error_codes::error_codes >( write_attribute_at( { 0x06 } ) ) == bluetoe::error_codes::out_of_range );\n        BOOST_CHECK( !free_write_bool_handler_called );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( write_bool_to_small, reset_bool< free_write_bool_char > )\n    {\n        BOOST_CHECK( static_cast< bluetoe::error_codes::error_codes >( write_attribute_at( {} ) ) == bluetoe::error_codes::invalid_attribute_value_length );\n        BOOST_CHECK( !free_write_bool_handler_called );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( write_bool_to_large, reset_bool< free_write_bool_char > )\n    {\n        BOOST_CHECK( static_cast< bluetoe::error_codes::error_codes >( write_attribute_at( { 0x00, 0x00 } ) ) == bluetoe::error_codes::invalid_attribute_value_length );\n        BOOST_CHECK( !free_write_bool_handler_called );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( write_bool_passing_return_value, reset_bool< free_write_bool_char > )\n    {\n        free_write_result = 32;\n        BOOST_CHECK( write_attribute_at( { 0x00 } ) == static_cast< bluetoe::details::attribute_access_result >( 32 ) );\n    }\n\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE( free_write_handler )\n\n\n    // that's how JSON looks in C++ ;-)\n    using supported_types = boost::mpl::list<\n        std::tuple< std::uint8_t,\n            // valid pairs\n            std::tuple<\n                std::tuple< test::tuple< 0x22 >, std::integral_constant< std::uint8_t, 34 > >,\n                std::tuple< test::tuple< 0x00 >, std::integral_constant< std::uint8_t, 0 > >,\n                std::tuple< test::tuple< 0xff >, std::integral_constant< std::uint8_t, 255 > >\n            >,\n            // wrong size examples\n            std::tuple<\n                test::tuple<>, test::tuple< 0x00, 0x00 >\n            >\n        >,\n        std::tuple< std::int8_t,\n            // valid pairs\n            std::tuple<\n                std::tuple< test::tuple< 0x22 >, std::integral_constant< std::int8_t, 34 > >,\n                std::tuple< test::tuple< 0x00 >, std::integral_constant< std::int8_t, 0 > >,\n                std::tuple< test::tuple< 0x80 >, std::integral_constant< std::int8_t, -128 > >,\n                std::tuple< test::tuple< 0xff >, std::integral_constant< std::int8_t, -1 > >\n            >,\n            // wrong size examples\n            std::tuple<\n                test::tuple<>, test::tuple< 0x00, 0x00 >\n            >\n        >,\n        std::tuple< std::uint16_t,\n            // valid pairs\n            std::tuple<\n                std::tuple< test::tuple< 0x22, 0x44 >, std::integral_constant< std::uint16_t, 0x4422 > >,\n                std::tuple< test::tuple< 0x00, 0x00 >, std::integral_constant< std::uint16_t, 0x0000 > >,\n                std::tuple< test::tuple< 0xff, 0xff >, std::integral_constant< std::uint16_t, 0xffff > >\n            >,\n            // wrong size examples\n            std::tuple<\n                test::tuple< 0x00 >, test::tuple< 0x00, 0x00, 0x00 >\n            >\n        >,\n        std::tuple< std::int16_t,\n            // valid pairs\n            std::tuple<\n                std::tuple< test::tuple< 0x22, 0x44 >, std::integral_constant< std::int16_t, 0x4422 > >,\n                std::tuple< test::tuple< 0x00, 0x00 >, std::integral_constant< std::int16_t, 0x0000 > >,\n                std::tuple< test::tuple< 0xff, 0xff >, std::integral_constant< std::int16_t, -1 > >\n            >,\n            // wrong size examples\n            std::tuple<\n                test::tuple< 0x00 >, test::tuple< 0x00, 0x00, 0x00 >\n            >\n        >,\n        std::tuple< std::uint32_t,\n            // valid pairs\n            std::tuple<\n                std::tuple< test::tuple< 0xF0, 0x1A, 0x22, 0x44 >, std::integral_constant< std::uint32_t, 0x44221AF0 > >,\n                std::tuple< test::tuple< 0x00, 0x00, 0x00, 0x00 >, std::integral_constant< std::uint32_t, 0x00000000 > >,\n                std::tuple< test::tuple< 0xff, 0xff, 0xff, 0xff >, std::integral_constant< std::uint32_t, 0xFFFFFFFF > >\n            >,\n            // wrong size examples\n            std::tuple<\n                test::tuple< 0x00, 0x00, 0x00 >,\n                test::tuple< 0x00, 0x00, 0x00, 0x00, 0x00 >\n            >\n        >,\n        std::tuple< std::int32_t,\n            // valid pairs\n            std::tuple<\n                std::tuple< test::tuple< 0xF0, 0x1A, 0x22, 0x44 >, std::integral_constant< std::int32_t, 0x44221AF0 > >,\n                std::tuple< test::tuple< 0x00, 0x00, 0x00, 0x00 >, std::integral_constant< std::int32_t, 0x00000000 > >,\n                std::tuple< test::tuple< 0xff, 0xff, 0xff, 0xff >, std::integral_constant< std::int32_t, -1 > >\n            >,\n            // wrong size examples\n            std::tuple<\n                test::tuple< 0x00, 0x00, 0x00 >,\n                test::tuple< 0x00, 0x00, 0x00, 0x00, 0x00 >\n            >\n        >,\n        std::tuple< std::uint64_t,\n            // valid pairs\n            std::tuple<\n                std::tuple< test::tuple< 0xF0, 0x1A, 0x22, 0x44, 0x01, 0x02, 0x03, 0x04 >, std::integral_constant< std::uint64_t, 0x0403020144221AF0 > >,\n                std::tuple< test::tuple< 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 >, std::integral_constant< std::uint64_t, 0x0000000000000000 > >,\n                std::tuple< test::tuple< 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff >, std::integral_constant< std::uint64_t, 0xFFFFFFFFFFFFFFFF > >\n            >,\n            // wrong size examples\n            std::tuple<\n                test::tuple< 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 >,\n                test::tuple< 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 >\n            >\n        >,\n        std::tuple< std::int64_t,\n            // valid pairs\n            std::tuple<\n                std::tuple< test::tuple< 0xF0, 0x1A, 0x22, 0x44, 0x01, 0x02, 0x03, 0x04 >, std::integral_constant< std::int64_t, 0x0403020144221AF0 > >,\n                std::tuple< test::tuple< 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 >, std::integral_constant< std::int64_t, 0x0000000000000000 > >,\n                std::tuple< test::tuple< 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff >, std::integral_constant< std::int64_t, -1 > >\n            >,\n            // wrong size examples\n            std::tuple<\n                test::tuple< 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 >,\n                test::tuple< 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 >\n            >\n        >\n    >;\n\n    template < typename T >\n    struct free_write_handler\n    {\n        static void init()\n        {\n            result          = 0;\n            written_value   = T{};\n            handler_called  = false;\n        }\n\n        free_write_handler()\n        {\n            init();\n        };\n\n        static std::uint8_t result;\n        static T            written_value;\n        static bool         handler_called;\n\n        static std::uint8_t handler( T v )\n        {\n            BOOST_REQUIRE( !handler_called );\n            written_value  = v;\n            handler_called = true;\n\n            return result;\n        }\n    };\n\n    template < typename T >\n    std::uint8_t free_write_handler< T >::result;\n\n    template < typename T >\n    T            free_write_handler< T >::written_value;\n\n    template < typename T >\n    bool         free_write_handler< T >::handler_called;\n\n    template < class T >\n    using free_write_characteristic =\n        bluetoe::characteristic<\n            bluetoe::characteristic_uuid16< 0x1245 >,\n            bluetoe::free_write_handler<\n                T, &free_write_handler< T >::handler\n            >\n        >;\n\n    template < typename T >\n    struct test_valid_value : access_attributes< free_write_characteristic< T > >\n    {\n        template< typename Pair >\n        void each()\n        {\n            free_write_handler< T >::init();\n\n            using Input          = typename std::tuple_element< 0, Pair >::type;\n            using ExpectedOutput = typename std::tuple_element< 1, Pair >::type;\n\n            const std::vector< std::uint8_t > data = Input::values();\n\n            BOOST_CHECK( this->write_attribute_at( &data[ 0 ], &data[ data.size() ] ) == bluetoe::details::attribute_access_result::success );\n            BOOST_CHECK_EQUAL( ExpectedOutput::value, free_write_handler< T >::written_value );\n            BOOST_CHECK( free_write_handler< T >::handler_called );\n        }\n    };\n\n    BOOST_AUTO_TEST_CASE_TEMPLATE( write_free_handlers_check_valid_values, Fixtures, supported_types )\n    {\n        using Type          = typename std::tuple_element< 0, Fixtures >::type;\n        using ValidValues   = typename std::tuple_element< 1, Fixtures >::type;\n\n        bluetoe::details::for_< ValidValues >::each( test_valid_value< Type >() );\n    }\n\n    template < typename T >\n    struct test_wrong_size : access_attributes< free_write_characteristic< T > >\n    {\n        template< typename Input >\n        void each()\n        {\n            free_write_handler< T >::init();\n\n            const std::vector< std::uint8_t > data = Input::values();\n\n            BOOST_CHECK( this->write_attribute_at( &data[ 0 ], &data[ data.size() ] ) == bluetoe::details::attribute_access_result::invalid_attribute_value_length );\n            BOOST_CHECK( !free_write_handler< T >::handler_called );\n        }\n    };\n\n    BOOST_AUTO_TEST_CASE_TEMPLATE( write_free_handlers_wrong_size, Fixtures, supported_types )\n    {\n        using Type          = typename std::tuple_element< 0, Fixtures >::type;\n        using InValidValues = typename std::tuple_element< 2, Fixtures >::type;\n\n        bluetoe::details::for_< InValidValues >::each( test_wrong_size< Type >() );\n    }\n\n    template < typename T >\n    struct test_return_value : access_attributes< free_write_characteristic< T > >\n    {\n        template< typename Pair >\n        void each()\n        {\n            free_write_handler< T >::init();\n            free_write_handler< T >::result = 42;\n\n            using Input          = typename std::tuple_element< 0, Pair >::type;\n\n            const std::vector< std::uint8_t > data = Input::values();\n\n            BOOST_CHECK( static_cast< int >( this->write_attribute_at( &data[ 0 ], &data[ data.size() ] ) ) == 42 );\n        }\n    };\n\n    BOOST_AUTO_TEST_CASE_TEMPLATE( write_free_handlers_check_return_value, Fixtures, supported_types )\n    {\n        using Type          = typename std::tuple_element< 0, Fixtures >::type;\n        using ValidValues   = typename std::tuple_element< 1, Fixtures >::type;\n\n        bluetoe::details::for_< ValidValues >::each( test_return_value< Type >() );\n    }\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "tests/ring_tests.cpp",
    "content": "#include <bluetoe/ring.hpp>\n\n#define BOOST_TEST_MODULE\n#include <boost/test/included/unit_test.hpp>\n\nusing ring_t = bluetoe::details::ring< 3u, std::string >;\n\nBOOST_FIXTURE_TEST_CASE( default_empty, ring_t )\n{\n    std::string d;\n    BOOST_CHECK( !try_pop( d ) );\n}\n\nBOOST_FIXTURE_TEST_CASE( default_capacity, ring_t )\n{\n    std::string d;\n    BOOST_CHECK( try_push( d ) );\n}\n\nBOOST_FIXTURE_TEST_CASE( fill, ring_t )\n{\n    std::string d1, d2, d3, d4;\n    BOOST_CHECK( try_push( d1 ) );\n    BOOST_CHECK( try_push( d2 ) );\n    BOOST_CHECK( try_push( d3 ) );\n    BOOST_CHECK( !try_push( d4 ) );\n}\n\nBOOST_FIXTURE_TEST_CASE( push_and_pop, ring_t )\n{\n    std::string in = \"Hallo\";\n    BOOST_CHECK( try_push( in ) );\n\n    std::string out;\n    BOOST_CHECK( try_pop( out ) );\n\n    BOOST_CHECK_EQUAL( in, out );\n    BOOST_CHECK( !try_pop( out ) );\n}\n\nBOOST_FIXTURE_TEST_CASE( around, ring_t )\n{\n    std::string d1 = \"1\", d2 = \"2\", d3 = \"3\", d4 = \"4\";\n    std::string out1, out2, out3, out4, out5;\n\n    BOOST_CHECK( try_push( d1 ) );\n    BOOST_CHECK( try_push( d2 ) );\n    BOOST_CHECK( try_push( d3 ) );\n    BOOST_CHECK( try_pop( out1 ) );\n    BOOST_CHECK( try_push( d4 ) );\n    BOOST_CHECK( try_pop( out2 ) );\n    BOOST_CHECK( try_pop( out3 ) );\n    BOOST_CHECK( try_pop( out4 ) );\n    BOOST_CHECK( !try_pop( out5 ) );\n\n    BOOST_CHECK_EQUAL( d1, out1 );\n    BOOST_CHECK_EQUAL( d2, out2 );\n    BOOST_CHECK_EQUAL( d3, out3 );\n    BOOST_CHECK_EQUAL( d4, out4 );\n}\n"
  },
  {
    "path": "tests/scattered_access_tests.cpp",
    "content": "#include <iostream>\n#include <bluetoe/scattered_access.hpp>\n#include \"hexdump.hpp\"\n\n#define BOOST_TEST_MODULE\n#include <boost/test/included/unit_test.hpp>\n\nnamespace blued = bluetoe::details;\n\nnamespace {\n    static const std::uint8_t a[] = { 1, 2 };\n    static const std::uint8_t b[] = { 3 };\n    static const std::uint8_t c[] = { 4, 5, 6 };\n}\n\nBOOST_AUTO_TEST_CASE( full_access )\n{\n    static const std::uint8_t expected_result[] = { 1, 2, 3, 4, 5, 6 };\n\n    std::uint8_t result[ 6 ] = { 0 };\n\n    blued::scattered_read_access( 0, a, b, c, &result[ 0 ], sizeof( result ) );\n\n    BOOST_CHECK_EQUAL_COLLECTIONS( std::begin( expected_result ), std::end( expected_result ), std::begin( result ), std::end( result ) );\n}\n\nBOOST_AUTO_TEST_CASE( truncated )\n{\n    static const std::uint8_t expected_result[] = { 1, 2, 3, 4, 5 };\n\n    std::uint8_t result[ 6 ] = { 0 };\n\n    blued::scattered_read_access( 0, a, b, c, &result[ 0 ], sizeof( result ) - 1 );\n\n    BOOST_CHECK_EQUAL_COLLECTIONS( std::begin( expected_result ), std::end( expected_result ), std::begin( result ), std::end( result ) - 1 );\n    BOOST_CHECK_EQUAL( result[ 5 ], 0 );\n}\n\nBOOST_AUTO_TEST_CASE( truncated_in_b )\n{\n    static const std::uint8_t expected_result[] = { 1, 2, 3 };\n\n    std::uint8_t result[ 6 ] = { 0 };\n\n    blued::scattered_read_access( 0, a, b, c, &result[ 0 ], sizeof( result ) - 3 );\n\n    BOOST_CHECK_EQUAL_COLLECTIONS( std::begin( expected_result ), std::end( expected_result ), std::begin( result ), std::end( result ) - 3 );\n    BOOST_CHECK_EQUAL( result[ 3 ], 0 );\n}\n\nBOOST_AUTO_TEST_CASE( truncated_to_zero )\n{\n    std::uint8_t result[ 6 ] = { 0 };\n\n    blued::scattered_read_access( 0, a, b, c, &result[ 0 ], 0 );\n\n    BOOST_CHECK_EQUAL( result[ 0 ], 0 );\n}\n\nBOOST_AUTO_TEST_CASE( full_access_with_offset )\n{\n    static const std::uint8_t expected_result[] = { 2, 3, 4, 5, 6 };\n\n    std::uint8_t result[ 5 ] = { 0 };\n\n    blued::scattered_read_access( 1, a, b, c, &result[ 0 ], sizeof( result ) );\n\n    BOOST_CHECK_EQUAL_COLLECTIONS( std::begin( expected_result ), std::end( expected_result ), std::begin( result ), std::end( result ) );\n}\n\nBOOST_AUTO_TEST_CASE( truncated_offset )\n{\n    static const std::uint8_t expected_result[] = { 2, 3, 4, 5 };\n\n    std::uint8_t result[ 5 ] = { 0 };\n\n    blued::scattered_read_access( 1, a, b, c, &result[ 0 ], sizeof( result ) - 1 );\n\n    BOOST_CHECK_EQUAL_COLLECTIONS( std::begin( expected_result ), std::end( expected_result ), std::begin( result ), std::end( result ) - 1 );\n    BOOST_CHECK_EQUAL( result[ 4 ], 0 );\n}\n\nBOOST_AUTO_TEST_CASE( truncated_with_offset_into_c )\n{\n    std::uint8_t result[ 2 ] = { 0 };\n\n    blued::scattered_read_access( 4, a, b, c, &result[ 0 ], 1 );\n\n    BOOST_CHECK_EQUAL( result[ 0 ], 5 );\n    BOOST_CHECK_EQUAL( result[ 1 ], 0 );\n}\n"
  },
  {
    "path": "tests/security_manager/CMakeLists.txt",
    "content": "function (add_and_register_sm_test target)\n    add_and_register_test(${target})\n    target_link_libraries(${target} PRIVATE bluetoe::link_layer )\nendfunction()\n\nadd_and_register_sm_test(pairing_tests aes.c)\nadd_and_register_sm_test(pairing_request_tests aes.c)\nadd_and_register_sm_test(pairing_confirm_tests aes.c)\nadd_and_register_sm_test(test_sm_tests aes.c)\nadd_and_register_sm_test(pairing_random_tests aes.c)\nadd_and_register_sm_test(key_distribution_tests aes.c)\nadd_and_register_sm_test(encryption_example_tests aes.c)\nadd_and_register_sm_test(public_key_exchange_tests)\nadd_and_register_sm_test(authentication_stage_tests1)\nadd_and_register_sm_test(authentication_stage_tests2)\nadd_and_register_sm_test(io_capabilities_tests)\nadd_and_register_sm_test(bonding_tests)"
  },
  {
    "path": "tests/security_manager/authentication_stage_tests1.cpp",
    "content": "#define BOOST_TEST_MODULE\n#include <boost/test/included/unit_test.hpp>\n\n#include <bluetoe/security_manager.hpp>\n\n#include \"test_sm.hpp\"\n\n\nBOOST_AUTO_TEST_CASE_TEMPLATE( pairing_confirm, Manager, test::lesc_managers )\n{\n    test::lesc_public_key_exchanged< Manager > fixture;\n\n    fixture.expected(\n        {\n            0x03,           // Pairing Confirm\n            0x99, 0x57, 0x89, 0x9b,\n            0xaa, 0x41, 0x1b, 0x45,\n            0x15, 0x8d, 0x58, 0xff,\n            0x73, 0x9b, 0x81, 0xd1\n        }\n    );\n}\n\nBOOST_AUTO_TEST_CASE_TEMPLATE( pairing_random_too_small, Manager, test::lesc_managers )\n{\n    test::lesc_pairing_confirmed< Manager > fixture;\n\n    fixture.expected(\n        {\n            0x04,           // Pairing Random\n            0x00, 0x00, 0x00, 0x00,\n            0x00, 0x00, 0x00, 0x00,\n            0x00, 0x00, 0x00, 0x00,\n            0x00, 0x00, 0x00\n        },\n        {\n            0x05,           // Pairing Failed\n            0x0A,           // Invalid Parameters\n        }\n    );\n}\n\nBOOST_AUTO_TEST_CASE_TEMPLATE( pairing_random_too_large, Manager, test::lesc_managers )\n{\n    test::lesc_pairing_confirmed< Manager > fixture;\n\n    fixture.expected(\n        {\n            0x04,           // Pairing Random\n            0x00, 0x00, 0x00, 0x00,\n            0x00, 0x00, 0x00, 0x00,\n            0x00, 0x00, 0x00, 0x00,\n            0x00, 0x00, 0x00, 0x00,\n            0x00\n        },\n        {\n            0x05,           // Pairing Failed\n            0x0A,           // Invalid Parameters\n        }\n    );\n}\n\nBOOST_AUTO_TEST_CASE_TEMPLATE( pairing_random_wrong_state, Manager, test::lesc_managers )\n{\n    test::lesc_public_key_exchanged< Manager > fixture;\n\n    fixture.expected_ignoring_output_available(\n        {\n            0x04,           // Pairing Random\n            0x00, 0x00, 0x00, 0x00,\n            0x00, 0x00, 0x00, 0x00,\n            0x00, 0x00, 0x00, 0x00,\n            0x00, 0x00, 0x00, 0x00,\n        },\n        {\n            0x05,           // Pairing Failed\n            0x08,           // Unspecified Reason\n        }\n    );\n}\n\nBOOST_AUTO_TEST_CASE_TEMPLATE( pairing_random, Manager, test::lesc_managers )\n{\n    test::lesc_pairing_confirmed< Manager > fixture;\n\n    // Na, Nb\n    fixture.expected(\n        // initiator nonce is not part of the Pairing confirm value)\n        {\n            0x04,           // Pairing Random\n            0xcf, 0xc4, 0x3d, 0xff,\n            0xf7, 0x83, 0x65, 0x21,\n            0x6e, 0x5f, 0xa7, 0x25,\n            0xcc, 0xe7, 0xe8, 0xa6\n        },\n        {\n            0x04,           // Pairing Random\n            0xab, 0xae, 0x2b, 0x71,\n            0xec, 0xb2, 0xff, 0xff,\n            0x3e, 0x73, 0x77, 0xd1,\n            0x54, 0x84, 0xcb, 0xd5\n        }\n    );\n}\n\nstruct pass_key_display_t {\n    pass_key_display_t()\n        : displayed_pass_key( ~0 )\n        , called( false )\n    {\n    }\n\n    void sm_pairing_numeric_output( int pass_key )\n    {\n        BOOST_REQUIRE( !called );\n        called = true;\n        displayed_pass_key = pass_key;\n    }\n\n    int displayed_pass_key;\n    bool called;\n} pass_key_display;\n\nstruct yes_no_input_t\n{\n    void sm_pairing_yes_no( bluetoe::pairing_yes_no_response& response )\n    {\n        response.yes_no_response( yes_no_response );\n    }\n\n    bool yes_no_response = true;\n} yes_no_input;\n\nusing lesc_security_manager_with_display_and_yes_no = test::lesc_security_manager< 65,\n    bluetoe::pairing_numeric_output< pass_key_display_t, pass_key_display >,\n    bluetoe::pairing_yes_no< yes_no_input_t, yes_no_input > >;\n\nusing security_manager_with_display_and_yes_no = test::security_manager< 65,\n    bluetoe::pairing_numeric_output< pass_key_display_t, pass_key_display >,\n    bluetoe::pairing_yes_no< yes_no_input_t, yes_no_input > >;\n\n\nusing lesc_security_managers_with_display_and_yes_no = std::tuple<\n    lesc_security_manager_with_display_and_yes_no,\n    security_manager_with_display_and_yes_no\n>;\n\ntemplate < bool YesNoResponse, class BaseFixture >\nstruct lesc_security_manager_with_display_and_yes_no_paired : BaseFixture\n{\n    lesc_security_manager_with_display_and_yes_no_paired()\n    {\n        pass_key_display.called = false;\n        yes_no_input.yes_no_response = YesNoResponse;\n\n        this->expected(\n            {\n                0x01,       // Pairing request\n                0x01,       // DisplayYesNo\n                0x00,       // OOB Authentication data not present\n                0x08,       // No Bonding, No MITM, SC = 1\n                0x10,       // Maximum Encryption Key Size\n                0x00,       // Initiator Key Distribution\n                0x00        // Responder Key Distribution\n            },\n            {\n                0x02,       // Pairing Response\n                0x01,       // DisplayYesNo\n                0x00,       // OOB Authentication data not present\n                0x08,       // No Bonding, MITM = 0, SC = 1, Keypress = 0\n                0x10,       // Maximum Encryption Key Size\n                0x00,       // Initiator Key Distribution\n                0x00        // Responder Key Distribution\n            }\n        );\n    }\n};\n\nBOOST_AUTO_TEST_CASE_TEMPLATE( lesc_numeric_comparison_pairing_public_key_exchange, Fixture, lesc_security_managers_with_display_and_yes_no )\n{\n    lesc_security_manager_with_display_and_yes_no_paired< true, Fixture > fixture;\n\n    fixture.expected(\n        {\n            0x0C,                   // Pairing Public Key\n            // Public Key X\n            0xe6, 0x9d, 0x35, 0x0e,\n            0x48, 0x01, 0x03, 0xcc,\n            0xdb, 0xfd, 0xf4, 0xac,\n            0x11, 0x91, 0xf4, 0xef,\n            0xb9, 0xa5, 0xf9, 0xe9,\n            0xa7, 0x83, 0x2c, 0x5e,\n            0x2c, 0xbe, 0x97, 0xf2,\n            0xd2, 0x03, 0xb0, 0x20,\n            // Public Key Y\n            0x8b, 0xd2, 0x89, 0x15,\n            0xd0, 0x8e, 0x1c, 0x74,\n            0x24, 0x30, 0xed, 0x8f,\n            0xc2, 0x45, 0x63, 0x76,\n            0x5c, 0x15, 0x52, 0x5a,\n            0xbf, 0x9a, 0x32, 0x63,\n            0x6d, 0xeb, 0x2a, 0x65,\n            0x49, 0x9c, 0x80, 0xdc\n        },\n        {\n            0x0C,                   // Pairing Public Key\n            // Public Key X\n            0x90, 0xa1, 0xaa, 0x2f,\n            0xb2, 0x77, 0x90, 0x55,\n            0x9f, 0xa6, 0x15, 0x86,\n            0xfd, 0x8a, 0xb5, 0x47,\n            0x00, 0x4c, 0x9e, 0xf1,\n            0x84, 0x22, 0x59, 0x09,\n            0x96, 0x1d, 0xaf, 0x1f,\n            0xf0, 0xf0, 0xa1, 0x1e,\n            // Public Key Y\n            0x4a, 0x21, 0xb1, 0x15,\n            0xf9, 0xaf, 0x89, 0x5f,\n            0x76, 0x36, 0x8e, 0xe2,\n            0x30, 0x11, 0x2d, 0x47,\n            0x60, 0x51, 0xb8, 0x9a,\n            0x3a, 0x70, 0x56, 0x73,\n            0x37, 0xad, 0x9d, 0x42,\n            0x3e, 0xf3, 0x55, 0x4c,\n        }\n    );\n}\n\ntemplate < bool YesNoResponse, class BaseFixture >\nstruct lesc_security_manager_with_display_and_yes_no_key_exchanged : lesc_security_manager_with_display_and_yes_no_paired< YesNoResponse, BaseFixture >\n{\n    lesc_security_manager_with_display_and_yes_no_key_exchanged()\n    {\n        this->expected(\n            {\n                0x0C,                   // Pairing Public Key\n                // Public Key X\n                0xe6, 0x9d, 0x35, 0x0e,\n                0x48, 0x01, 0x03, 0xcc,\n                0xdb, 0xfd, 0xf4, 0xac,\n                0x11, 0x91, 0xf4, 0xef,\n                0xb9, 0xa5, 0xf9, 0xe9,\n                0xa7, 0x83, 0x2c, 0x5e,\n                0x2c, 0xbe, 0x97, 0xf2,\n                0xd2, 0x03, 0xb0, 0x20,\n                // Public Key Y\n                0x8b, 0xd2, 0x89, 0x15,\n                0xd0, 0x8e, 0x1c, 0x74,\n                0x24, 0x30, 0xed, 0x8f,\n                0xc2, 0x45, 0x63, 0x76,\n                0x5c, 0x15, 0x52, 0x5a,\n                0xbf, 0x9a, 0x32, 0x63,\n                0x6d, 0xeb, 0x2a, 0x65,\n                0x49, 0x9c, 0x80, 0xdc\n            },\n            {\n                0x0C,                   // Pairing Public Key\n                // Public Key X\n                0x90, 0xa1, 0xaa, 0x2f,\n                0xb2, 0x77, 0x90, 0x55,\n                0x9f, 0xa6, 0x15, 0x86,\n                0xfd, 0x8a, 0xb5, 0x47,\n                0x00, 0x4c, 0x9e, 0xf1,\n                0x84, 0x22, 0x59, 0x09,\n                0x96, 0x1d, 0xaf, 0x1f,\n                0xf0, 0xf0, 0xa1, 0x1e,\n                // Public Key Y\n                0x4a, 0x21, 0xb1, 0x15,\n                0xf9, 0xaf, 0x89, 0x5f,\n                0x76, 0x36, 0x8e, 0xe2,\n                0x30, 0x11, 0x2d, 0x47,\n                0x60, 0x51, 0xb8, 0x9a,\n                0x3a, 0x70, 0x56, 0x73,\n                0x37, 0xad, 0x9d, 0x42,\n                0x3e, 0xf3, 0x55, 0x4c,\n            }\n        );\n    }\n};\n\nBOOST_AUTO_TEST_CASE_TEMPLATE( lesc_numeric_comparison_commitment_and_random, Fixture, lesc_security_managers_with_display_and_yes_no )\n{\n    lesc_security_manager_with_display_and_yes_no_key_exchanged< true, Fixture > fixture;\n\n    fixture.expected(\n        {\n            0x03,           // Pairing Confirm\n            0x99, 0x57, 0x89, 0x9b,\n            0xaa, 0x41, 0x1b, 0x45,\n            0x15, 0x8d, 0x58, 0xff,\n            0x73, 0x9b, 0x81, 0xd1\n        }\n    );\n\n    // Na, Nb\n    fixture.expected(\n        // initiator nonce is not part of the Pairing confirm value)\n        {\n            0x04,           // Pairing Random\n            0xcf, 0xc4, 0x3d, 0xff,\n            0xf7, 0x83, 0x65, 0x21,\n            0x6e, 0x5f, 0xa7, 0x25,\n            0xcc, 0xe7, 0xe8, 0xa6\n        },\n        {\n            0x04,           // Pairing Random\n            0xab, 0xae, 0x2b, 0x71,\n            0xec, 0xb2, 0xff, 0xff,\n            0x3e, 0x73, 0x77, 0xd1,\n            0x54, 0x84, 0xcb, 0xd5\n        }\n    );\n}\n\ntemplate < bool YesNoResponse, class BaseFixture >\nstruct lesc_security_manager_with_display_and_yes_commitment_and_random : lesc_security_manager_with_display_and_yes_no_key_exchanged< YesNoResponse, BaseFixture >\n{\n    lesc_security_manager_with_display_and_yes_commitment_and_random()\n    {\n        this->expected(\n            {\n                0x03,           // Pairing Confirm\n                0x99, 0x57, 0x89, 0x9b,\n                0xaa, 0x41, 0x1b, 0x45,\n                0x15, 0x8d, 0x58, 0xff,\n                0x73, 0x9b, 0x81, 0xd1\n            }\n        );\n\n        // Na, Nb\n        this->expected(\n            // initiator nonce is not part of the Pairing confirm value)\n            {\n                0x04,           // Pairing Random\n                0xcf, 0xc4, 0x3d, 0xff,\n                0xf7, 0x83, 0x65, 0x21,\n                0x6e, 0x5f, 0xa7, 0x25,\n                0xcc, 0xe7, 0xe8, 0xa6\n            },\n            {\n                0x04,           // Pairing Random\n                0xab, 0xae, 0x2b, 0x71,\n                0xec, 0xb2, 0xff, 0xff,\n                0x3e, 0x73, 0x77, 0xd1,\n                0x54, 0x84, 0xcb, 0xd5\n            }\n        );\n    }\n};\n\nBOOST_AUTO_TEST_CASE_TEMPLATE( lesc_numeric_comparison_user_check_ok, Fixture, lesc_security_managers_with_display_and_yes_no )\n{\n    lesc_security_manager_with_display_and_yes_commitment_and_random< true, Fixture > fixture;\n\n    const std::array< std::uint8_t, 32 > pka = {{\n        0xe6, 0x9d, 0x35, 0x0e,\n        0x48, 0x01, 0x03, 0xcc,\n        0xdb, 0xfd, 0xf4, 0xac,\n        0x11, 0x91, 0xf4, 0xef,\n        0xb9, 0xa5, 0xf9, 0xe9,\n        0xa7, 0x83, 0x2c, 0x5e,\n        0x2c, 0xbe, 0x97, 0xf2,\n        0xd2, 0x03, 0xb0, 0x20\n    }};\n\n    const std::array< std::uint8_t, 32 > pkb = {{\n        0x90, 0xa1, 0xaa, 0x2f,\n        0xb2, 0x77, 0x90, 0x55,\n        0x9f, 0xa6, 0x15, 0x86,\n        0xfd, 0x8a, 0xb5, 0x47,\n        0x00, 0x4c, 0x9e, 0xf1,\n        0x84, 0x22, 0x59, 0x09,\n        0x96, 0x1d, 0xaf, 0x1f,\n        0xf0, 0xf0, 0xa1, 0x1e\n    }};\n\n    const std::array< std::uint8_t, 16 > na = {{\n        0xcf, 0xc4, 0x3d, 0xff,\n        0xf7, 0x83, 0x65, 0x21,\n        0x6e, 0x5f, 0xa7, 0x25,\n        0xcc, 0xe7, 0xe8, 0xa6\n    }};\n\n    const std::array< std::uint8_t, 16 > nb = {{\n        0xab, 0xae, 0x2b, 0x71,\n        0xec, 0xb2, 0xff, 0xff,\n        0x3e, 0x73, 0x77, 0xd1,\n        0x54, 0x84, 0xcb, 0xd5\n    }};\n\n    const auto bit20mask = 0xfffff;\n\n    const auto expected_key = fixture.g2( pka.data(), pkb.data(), na, nb );\n    BOOST_CHECK( pass_key_display.called );\n    BOOST_CHECK_EQUAL(\n        static_cast< int >( pass_key_display.displayed_pass_key & bit20mask ),\n        static_cast< int >( expected_key & bit20mask ) );\n}\n\nBOOST_AUTO_TEST_CASE_TEMPLATE( lesc_numeric_comparison_user_check_fail, Fixture, lesc_security_managers_with_display_and_yes_no )\n{\n    lesc_security_manager_with_display_and_yes_no_key_exchanged< false, Fixture > fixture;\n\n    fixture.expected(\n        {\n            0x03,           // Pairing Confirm\n            0x99, 0x57, 0x89, 0x9b,\n            0xaa, 0x41, 0x1b, 0x45,\n            0x15, 0x8d, 0x58, 0xff,\n            0x73, 0x9b, 0x81, 0xd1\n        }\n    );\n\n    // Na, Nb\n    fixture.expected(\n        // initiator nonce is not part of the Pairing confirm value)\n        {\n            0x04,           // Pairing Random\n            0xcf, 0xc4, 0x3d, 0xff,\n            0xf7, 0x83, 0x65, 0x21,\n            0x6e, 0x5f, 0xa7, 0x25,\n            0xcc, 0xe7, 0xe8, 0xa6\n        },\n        {\n            0x05,           // Pairing failed\n            0x01            // Passkey Entry Failed\n        }\n    );\n}\n"
  },
  {
    "path": "tests/security_manager/authentication_stage_tests2.cpp",
    "content": "#define BOOST_TEST_MODULE\n#include <boost/test/included/unit_test.hpp>\n\n#include <bluetoe/security_manager.hpp>\n\n#include \"test_sm.hpp\"\n\nBOOST_AUTO_TEST_CASE_TEMPLATE( pairing_dhkey_check_too_small, Manager, test::lesc_managers )\n{\n    test::lesc_pairing_random_exchanged< Manager > fixture;\n\n    fixture.expected(\n        {\n            0x0D,           // DHKey Check\n            0x00, 0x00, 0x00, 0x00,\n            0x00, 0x00, 0x00, 0x00,\n            0x00, 0x00, 0x00, 0x00,\n            0x00, 0x00, 0x00\n        },\n        {\n            0x05,           // Pairing Failed\n            0x0A,           // Invalid Parameters\n        }\n    );\n}\n\nBOOST_AUTO_TEST_CASE_TEMPLATE( pairing_dhkey_check_too_large, Manager, test::lesc_managers )\n{\n    test::lesc_pairing_random_exchanged< Manager > fixture;\n\n    fixture.expected(\n        {\n            0x0D,           // DHKey Check\n            0x00, 0x00, 0x00, 0x00,\n            0x00, 0x00, 0x00, 0x00,\n            0x00, 0x00, 0x00, 0x00,\n            0x00, 0x00, 0x00, 0x00,\n            0x00\n        },\n        {\n            0x05,           // Pairing Failed\n            0x0A,           // Invalid Parameters\n        }\n    );\n}\n\nBOOST_AUTO_TEST_CASE_TEMPLATE( pairing_dhkey_check_wrong_state, Manager, test::lesc_managers )\n{\n    test::lesc_pairing_confirmed< Manager > fixture;\n\n    fixture.expected(\n        {\n            0x0D,           // DHKey Check\n            0x00, 0x00, 0x00, 0x00,\n            0x00, 0x00, 0x00, 0x00,\n            0x00, 0x00, 0x00, 0x00,\n            0x00, 0x00, 0x00, 0x00\n        },\n        {\n            0x05,           // Pairing Failed\n            0x08,           // Unspecified Reason\n        }\n    );\n}\n\nBOOST_AUTO_TEST_CASE_TEMPLATE( pairing_dhkey_check_failed, Manager, test::lesc_managers )\n{\n    test::lesc_pairing_random_exchanged< Manager > fixture;\n\n    fixture.expected(\n        {\n            0x0D,           // DHKey Check\n            0x8a, 0x66, 0x11, 0x68,\n            0x49, 0xca, 0x39, 0x2d,\n            0x5d, 0x9b, 0xe1, 0x1e,\n            0x42, 0x38, 0xef, 0xd8  // <- last byte is of by 1\n        },\n        {\n            0x05,           // Pairing Failed\n            0x0b,           // DHKey check failed\n        }\n    );\n}\n\nBOOST_AUTO_TEST_CASE_TEMPLATE( pairing_dhkey_check_success, Manager, test::lesc_managers )\n{\n    test::lesc_pairing_random_exchanged< Manager > fixture;\n\n    fixture.expected(\n        {\n            0x0D,           // DHKey Check\n            0x68, 0xd6, 0x70, 0x63,\n            0xae, 0x09, 0x87, 0x88,\n            0xa0, 0x19, 0x56, 0xa0,\n            0xca, 0xf0, 0x5d, 0x9d\n        },\n        {\n            0x0D,           // DHKey Check\n            0xd4, 0x5b, 0xa2, 0x51,\n            0x11, 0x44, 0xd4, 0x69,\n            0x30, 0x2a, 0xe6, 0x43,\n            0x1d, 0x9a, 0x44, 0x1a\n        }\n    );\n\n    BOOST_CHECK( fixture.connection_data().state() == bluetoe::details::sm_pairing_state::pairing_completed );\n}\n\nclass pairing_io_t\n{\npublic:\n    void init()\n    {\n        displayed_pass_key_ = ~0;\n        response_ = nullptr;\n    }\n\n    pairing_io_t()\n    {\n        init();\n    }\n\n    void sm_pairing_yes_no( bluetoe::pairing_yes_no_response& response )\n    {\n        response_ = &response;\n    }\n\n    void sm_pairing_numeric_output( int pass_key )\n    {\n        displayed_pass_key_ = pass_key;\n    }\n\n    void response( bool r )\n    {\n        response_->yes_no_response( r );\n        response_ = nullptr;\n    }\n\nprivate:\n    int displayed_pass_key_;\n    bluetoe::pairing_yes_no_response* response_;\n} pairing_io;\n\ntemplate < class Manager >\nstruct with_display_and_yes_no_input : test::security_manager_base< Manager, test::all_security_functions, 65,\n    bluetoe::pairing_numeric_output< pairing_io_t, pairing_io >,\n    bluetoe::pairing_yes_no< pairing_io_t, pairing_io > >\n{\n    with_display_and_yes_no_input()\n    {\n        pairing_io.init();\n\n        // Feature Exchange\n        this->expected(\n            {\n                0x01,           // Pairing Request\n                0x01,           // IO Capability DisplayYesNo\n                0x00,           // OOB data flag (data not present)\n                0x08,           // Bonding, MITM = 0, SC = 1, Keypress = 0\n                0x10,           // Maximum Encryption Key Size (16)\n                0x07,           // Initiator Key Distribution\n                0x07,           // Responder Key Distribution (RFU)\n            },\n            {\n                0x02,           // response\n                0x01,           // DisplayYesNo\n                0x00,           // OOB Authentication data not present\n                0x08,           // Bonding, MITM = 0, SC = 1, Keypress = 0\n                0x10,           // Maximum Encryption Key Size\n                0x00,           // LinkKey\n                0x00            // LinkKey\n            }\n        );\n\n        // Public Key Exchange\n        this->expected(\n            {\n                0x0C,                   // Pairing Public Key\n                // Public Key X\n                0xe6, 0x9d, 0x35, 0x0e,\n                0x48, 0x01, 0x03, 0xcc,\n                0xdb, 0xfd, 0xf4, 0xac,\n                0x11, 0x91, 0xf4, 0xef,\n                0xb9, 0xa5, 0xf9, 0xe9,\n                0xa7, 0x83, 0x2c, 0x5e,\n                0x2c, 0xbe, 0x97, 0xf2,\n                0xd2, 0x03, 0xb0, 0x20,\n                // Public Key Y\n                0x8b, 0xd2, 0x89, 0x15,\n                0xd0, 0x8e, 0x1c, 0x74,\n                0x24, 0x30, 0xed, 0x8f,\n                0xc2, 0x45, 0x63, 0x76,\n                0x5c, 0x15, 0x52, 0x5a,\n                0xbf, 0x9a, 0x32, 0x63,\n                0x6d, 0xeb, 0x2a, 0x65,\n                0x49, 0x9c, 0x80, 0xdc\n            },\n            {\n                0x0C,                   // Pairing Public Key\n                // Public Key X\n                0x90, 0xa1, 0xaa, 0x2f,\n                0xb2, 0x77, 0x90, 0x55,\n                0x9f, 0xa6, 0x15, 0x86,\n                0xfd, 0x8a, 0xb5, 0x47,\n                0x00, 0x4c, 0x9e, 0xf1,\n                0x84, 0x22, 0x59, 0x09,\n                0x96, 0x1d, 0xaf, 0x1f,\n                0xf0, 0xf0, 0xa1, 0x1e,\n                // Public Key Y\n                0x4a, 0x21, 0xb1, 0x15,\n                0xf9, 0xaf, 0x89, 0x5f,\n                0x76, 0x36, 0x8e, 0xe2,\n                0x30, 0x11, 0x2d, 0x47,\n                0x60, 0x51, 0xb8, 0x9a,\n                0x3a, 0x70, 0x56, 0x73,\n                0x37, 0xad, 0x9d, 0x42,\n                0x3e, 0xf3, 0x55, 0x4c,\n            }\n        );\n\n        // LESC Pairing Confirm\n        this->expected(\n            {\n                0x03,           // Pairing Confirm\n                0x99, 0x57, 0x89, 0x9b,\n                0xaa, 0x41, 0x1b, 0x45,\n                0x15, 0x8d, 0x58, 0xff,\n                0x73, 0x9b, 0x81, 0xd1\n            }\n        );\n\n        // Pairing Random Exchange\n        this->expected(\n            {\n                0x04,           // Pairing Random\n                0x00, 0x00, 0x00, 0x00,\n                0x00, 0x00, 0x00, 0x00,\n                0x00, 0x00, 0x00, 0x00,\n                0x00, 0x00, 0x00, 0x00\n            },\n            {\n                0x04,           // Pairing Random\n                0xab, 0xae, 0x2b, 0x71,\n                0xec, 0xb2, 0xff, 0xff,\n                0x3e, 0x73, 0x77, 0xd1,\n                0x54, 0x84, 0xcb, 0xd5\n            }\n        );\n    }\n};\n\nBOOST_AUTO_TEST_CASE_TEMPLATE( async_numeric_compairson_failed, Manager, test::lesc_managers )\n{\n    with_display_and_yes_no_input< Manager > fixture;\n\n    fixture.expected(\n        {\n            0x0D,           // DHKey Check\n            0x68, 0xd6, 0x70, 0x63,\n            0xae, 0x09, 0x87, 0x88,\n            0xa0, 0x19, 0x56, 0xa0,\n            0xca, 0xf0, 0x5d, 0x9d\n        },\n        // No Output expected\n        {}\n    );\n\n    pairing_io.response( false );\n\n    fixture.expected(\n        {\n            0x05,           // Pairing Failed\n            0x01            // Passkey Entry Failed\n        }\n    );\n}\n\nBOOST_AUTO_TEST_CASE_TEMPLATE( async_numeric_compairson_success, Manager, test::lesc_managers )\n{\n    with_display_and_yes_no_input< Manager > fixture;\n\n    fixture.expected(\n        {\n            0x0D,           // DHKey Check\n            0x68, 0xd6, 0x70, 0x63,\n            0xae, 0x09, 0x87, 0x88,\n            0xa0, 0x19, 0x56, 0xa0,\n            0xca, 0xf0, 0x5d, 0x9d\n        },\n        // No Output expected\n        {}\n    );\n\n    pairing_io.response( true );\n\n    fixture.expected(\n        {\n            0x0D,           // DHKey Check\n            0xce, 0x16, 0xae, 0x4e,\n            0x27, 0x54, 0x6b, 0x0d,\n            0x07, 0x7d, 0xd1, 0xd6,\n            0x07, 0xeb, 0x2d, 0x84\n        }\n    );\n}\n\nBOOST_AUTO_TEST_CASE_TEMPLATE( sync_numeric_compairson_success, Manager, test::lesc_managers )\n{\n    with_display_and_yes_no_input< Manager > fixture;\n    pairing_io.response( true );\n\n    fixture.expected_ignoring_output_available(\n        {\n            0x0D,           // DHKey Check\n            0x68, 0xd6, 0x70, 0x63,\n            0xae, 0x09, 0x87, 0x88,\n            0xa0, 0x19, 0x56, 0xa0,\n            0xca, 0xf0, 0x5d, 0x9d\n        },\n        {\n            0x0D,           // DHKey Check\n            0xce, 0x16, 0xae, 0x4e,\n            0x27, 0x54, 0x6b, 0x0d,\n            0x07, 0x7d, 0xd1, 0xd6,\n            0x07, 0xeb, 0x2d, 0x84\n        }\n    );\n\n    std::uint8_t buffer[ 200 ];\n    std::size_t  size = 200;\n    fixture.l2cap_output( buffer, size , fixture.connection_data_ );\n    BOOST_CHECK( size == 0 );\n}\n\nBOOST_AUTO_TEST_CASE_TEMPLATE( sync_numeric_compairson_fail, Manager, test::lesc_managers )\n{\n    with_display_and_yes_no_input< Manager > fixture;\n    pairing_io.response( false );\n\n    fixture.expected_ignoring_output_available(\n        {\n            0x0D,           // DHKey Check\n            0x68, 0xd6, 0x70, 0x63,\n            0xae, 0x09, 0x87, 0x88,\n            0xa0, 0x19, 0x56, 0xa0,\n            0xca, 0xf0, 0x5d, 0x9d\n        },\n        {\n            0x05,           // Pairing Failed\n            0x01            // Passkey Entry Failed\n        }\n    );\n\n    std::uint8_t buffer[ 200 ];\n    std::size_t  size = 200;\n    fixture.l2cap_output( buffer, size , fixture.connection_data_ );\n    BOOST_CHECK( size == 0 );\n}\n"
  },
  {
    "path": "tests/security_manager/bonding_tests.cpp",
    "content": "#define BOOST_TEST_MODULE\n#include <boost/test/included/unit_test.hpp>\n\n#include <bluetoe/security_manager.hpp>\n\n#include \"test_sm.hpp\"\n\nstruct data_base_t\n{\n    template < class Radio >\n    bluetoe::details::longterm_key_t create_new_bond(\n        Radio& /*radio*/, const bluetoe::link_layer::device_address& mac )\n    {\n        creating_mac = mac;\n\n        return bluetoe::details::longterm_key_t{\n            .longterm_key = {\n                0x01, 0x02, 0x03, 0x04,\n                0x11, 0x12, 0x13, 0x14,\n                0x21, 0x22, 0x23, 0x24,\n                0x31, 0x32, 0x33, 0x34\n            },\n            .rand         = 0x12345678aabbccddu,\n            .ediv         = 0x1122u\n        };\n    }\n\n    template < class Connection >\n    void store_bond(\n        const bluetoe::details::longterm_key_t& key,\n        const Connection& connection)\n    {\n        stored_bond_key = key;\n        stored_bond_mac = connection.remote_address();\n    }\n\n    std::pair< bool, bluetoe::details::uint128_t > find_key( std::uint16_t ediv, std::uint64_t rand, const bluetoe::link_layer::device_address& remote_address ) const\n    {\n        requesting_ediv = ediv;\n        requesting_rand = rand;\n        requesting_mac  = remote_address;\n\n        return stored_key;\n    }\n\n    std::pair< bool, bluetoe::details::uint128_t > stored_key = { false, {} };\n    mutable std::uint16_t requesting_ediv = ~0;\n    mutable std::uint64_t requesting_rand = ~0;\n    mutable bluetoe::link_layer::device_address requesting_mac;\n    mutable bluetoe::link_layer::device_address creating_mac;\n\n    bluetoe::details::longterm_key_t     stored_bond_key;\n    bluetoe::link_layer::device_address  stored_bond_mac;\n} data_base;\n\nstruct use_data_base : test::legacy_security_manager<\n    100u,\n    bluetoe::bonding_data_base< data_base_t, data_base > >\n{\n    use_data_base()\n    {\n        data_base = data_base_t();\n    }\n\n    using connection_data = channel_data_t< bluetoe::details::no_such_type >;\n\n    std::pair< bool, bluetoe::details::uint128_t > call_find_key( std::uint16_t ediv, std::uint64_t rand, const connection_data& connection ) const\n    {\n        return connection.find_key( ediv, rand );\n    }\n};\n\nBOOST_FIXTURE_TEST_CASE( no_key_stored, use_data_base )\n{\n    connection_data connection;\n    BOOST_CHECK( !call_find_key( 0, 0, connection ).first );\n}\n\nBOOST_FIXTURE_TEST_CASE( key_stored, use_data_base )\n{\n    connection_data connection;\n    data_base.stored_key = { true, { 0x12, 0x23, 0x34, 0x45 } };\n\n    const auto key = call_find_key( 47, 11, connection );\n\n    BOOST_CHECK( key.first );\n    BOOST_TEST( key.second == ( bluetoe::details::uint128_t{ 0x12, 0x23, 0x34, 0x45 } ) );\n    BOOST_TEST( data_base.requesting_ediv == 47u );\n    BOOST_TEST( data_base.requesting_rand == 11u );\n}\n\nBOOST_FIXTURE_TEST_CASE( bonding_is_requested_in_response, use_data_base )\n{\n    // Pairing request / response\n    expected(\n        {\n            0x01,                   // Pairing Request\n            0x01, 0x00, 0x08, 0x10, 0x07, 0x07\n        },\n        {\n            0x02,                   // Pairing Response\n            0x03, 0x00, 0x01, 0x10, 0x00, 0x01\n        }\n    );\n\n    // Pairing confirm\n    expected(\n        {\n            0x03,                   // Pairing Confirm\n            0x29, 0x99, 0xe1, 0x97,\n            0x95, 0x06, 0x67, 0x76,\n            0x66, 0xce, 0x0f, 0xf8,\n            0x95, 0xb9, 0x32, 0x83\n        },\n        {\n            0x03,                   // Pairing Confirm\n            0x29, 0x99, 0xe1, 0x97, // Confirm Value\n            0x95, 0x06, 0x67, 0x76,\n            0x66, 0xce, 0x0f, 0xf8,\n            0x95, 0xb9, 0x32, 0x83\n        }\n    );\n\n    // Pairing Random\n    expected(\n        {\n            0x04,                   // opcode\n            0xE0, 0x2E, 0x70, 0xC6,\n            0x4E, 0x27, 0x88, 0x63,\n            0x0E, 0x6F, 0xAD, 0x56,\n            0x21, 0xD5, 0x83, 0x57\n        },\n        {\n            0x04,                   // opcode\n            0xE0, 0x2E, 0x70, 0xC6,\n            0x4E, 0x27, 0x88, 0x63,\n            0x0E, 0x6F, 0xAD, 0x56,\n            0x21, 0xD5, 0x83, 0x57\n        }\n    );\n\n    // no key transmitted till the connection gets encrypted\n    expected({});\n\n    connection_data_.is_encrypted( true );\n\n    expected({\n        0x06,                   // Encryption Information\n        0x01, 0x02, 0x03, 0x04,\n        0x11, 0x12, 0x13, 0x14,\n        0x21, 0x22, 0x23, 0x24,\n        0x31, 0x32, 0x33, 0x34\n    });\n\n    expected({\n        0x07,                   // Central Identification\n        0x22, 0x11,             // EDIV\n        0xdd, 0xcc, 0xbb, 0xaa, // Rand\n        0x78, 0x56, 0x34, 0x12\n    });\n}"
  },
  {
    "path": "tests/security_manager/encryption_example_tests.cpp",
    "content": "#define BOOST_TEST_MODULE\n#include <boost/test/included/unit_test.hpp>\n\n#include <array>\n#include \"aes.h\"\n#include \"hexdump.hpp\"\n\nusing uint128_t = std::array< std::uint8_t, 16 >;\nusing uint64_t_  = std::array< std::uint8_t, 8 >;\nusing uint32_t_  = std::array< std::uint8_t, 4 >;\n\nstatic const uint128_t central_random_value = {\n    0xde, 0x15, 0x6b, 0xef, 0xb3, 0xd5, 0x8b, 0xdb,\n    0x58, 0x11, 0x8f, 0x3d, 0x49, 0xbd, 0x31, 0x0e };\n\nstatic const uint128_t peripheral_random_value = {\n    0x58, 0x44, 0xa0, 0xd4, 0x88, 0xd8, 0xc4, 0x7d,\n    0xd9, 0x51, 0x0e, 0x1d, 0x00, 0xa8, 0x9a, 0x64 };\n\nstatic const uint128_t short_term_key = {\n    0xa8, 0xb4, 0x33, 0x6b, 0x59, 0x91, 0x7e, 0x2c,\n    0xab, 0xa9, 0xfd, 0xd7, 0xc3, 0xb5, 0xd7, 0x12\n};\n\n\n// Mconfirm = c1(TK, Mrand,\n// Pairing Request command, Pairing Response command, initiating device address type, initiating device address, responding device address type, responding device address)\n\n// Sconfirm = c1(TK, Srand,\n// Pairing Request command, Pairing Response command,\n\nstatic uint128_t xor_( uint128_t a, uint128_t b )\n{\n    std::transform(\n        a.begin(), a.end(),\n        b.begin(),\n        a.begin(),\n        []( std::uint8_t a, std::uint8_t b ) -> std::uint8_t\n        {\n            return a xor b;\n        }\n    );\n\n    return a;\n}\n\nuint128_t r( const uint128_t& a )\n{\n    const uint128_t result{{\n        a[15], a[14], a[13], a[12],\n        a[11], a[10], a[ 9], a[ 8],\n        a[ 7], a[ 6], a[ 5], a[ 4],\n        a[ 3], a[ 2], a[ 1], a[ 0],\n    }};\n\n    return result;\n}\n\nuint128_t aes( uint128_t key, uint128_t data )\n{\n    AES_ctx ctx;\n    AES_init_ctx( &ctx, &key[ 0 ] );\n\n    AES_ECB_encrypt( &ctx, &data[ 0 ] );\n\n    return data;\n}\n\nuint128_t aes_le( uint128_t key, uint128_t data )\n{\n    key  = r( key );\n    data = r( data );\n\n    AES_ctx ctx;\n    AES_init_ctx( &ctx, &key[ 0 ] );\n\n    AES_ECB_encrypt( &ctx, &data[ 0 ] );\n\n    return r( data );\n}\n\nBOOST_AUTO_TEST_CASE( aes_test )\n{\n    const uint128_t key{{\n        0x0f, 0x0e, 0x0d, 0x0c,\n        0x0b, 0x0a, 0x09, 0x08,\n        0x07, 0x06, 0x05, 0x04,\n        0x03, 0x02, 0x01, 0x00\n    }};\n\n    const uint128_t input{{\n        0xff, 0xee, 0xdd, 0xcc,\n        0xbb, 0xaa, 0x99, 0x88,\n        0x77, 0x66, 0x55, 0x44,\n        0x33, 0x22, 0x11, 0x00\n    }};\n\n    const uint128_t expected{{\n        0x5a, 0xc5, 0xb4, 0x70,\n        0x80, 0xb7, 0xcd, 0xd8,\n        0x30, 0x04, 0x7b, 0x6a,\n        0xd8, 0xe0, 0xc4, 0x69\n    }};\n\n    const uint128_t output = aes_le( key, input );\n\n    BOOST_CHECK_EQUAL_COLLECTIONS(\n        output.begin(), output.end(), expected.begin(), expected.end() );\n}\n\nstatic uint128_t c1( uint128_t k, uint128_t r, uint128_t p1, uint128_t p2 )\n{\n    // c1 (k, r, preq, pres, iat, rat, ia, ra) = e(k, e(k, r XOR p1) XOR p2)\n    // p1 = pres || preq || rat’ || iat’\n    // p2 = padding || ia || ra\n    return aes_le(k, xor_( aes_le(k, xor_(r, p1)), p2) );\n}\n\nstatic void check_equal( uint128_t a, uint128_t b )\n{\n    BOOST_CHECK_EQUAL_COLLECTIONS( a.begin(), a.end(), b.begin(), b.end() );\n}\n\nBOOST_AUTO_TEST_CASE( test_c1 )\n{\n    // For example, if the 128-bit k is 0x00000000000000000000000000000000,\n    // the 128-bit value r is 0x5783D52156AD6F0E6388274EC6702EE0, the 128-bit\n    // value p1 is 0x05000800000302070710000001010001 and the 128-bit value\n    // p2 is 0x00000000A1A2A3A4A5A6B1B2B3B4B5B6 then the 128-bit output from\n    // the c1 function is 0x1e1e3fef878988ead2a74dc5bef13b86.\n\n    static const uint128_t k = {\n        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00\n    };\n\n    static const uint128_t r = {\n        0xE0, 0x2E, 0x70, 0xC6, 0x4E, 0x27, 0x88, 0x63,\n        0x0E, 0x6F, 0xAD, 0x56, 0x21, 0xD5, 0x83, 0x57\n    };\n\n    static const uint128_t p1 = {\n        0x01, 0x00, 0x01, 0x01, 0x00, 0x00, 0x10, 0x07,\n        0x07, 0x02, 0x03, 0x00, 0x00, 0x08, 0x00, 0x05\n    };\n\n    static const uint128_t p2 = {\n        0xB6, 0xB5, 0xB4, 0xB3, 0xB2, 0xB1, 0xA6, 0xA5,\n        0xA4, 0xA3, 0xA2, 0xA1, 0x00, 0x00, 0x00, 0x00\n    };\n\n    static const uint128_t expected = {\n        0x86, 0x3b, 0xf1, 0xbe, 0xc5, 0x4d, 0xa7, 0xd2,\n        0xea, 0x88, 0x89, 0x87, 0xef, 0x3f, 0x1e, 0x1e\n    };\n\n    check_equal( c1( k, r, p1, p2 ), expected );\n}\n\n// s1(k, r1, r2) = e(k, r’)\nstatic uint128_t s1( uint128_t k, uint128_t r1, uint128_t r2 )\n{\n    uint128_t r;\n    std::copy( r1.begin(), r1.begin() + 8, r.begin() + 8 );\n    std::copy( r2.begin(), r2.begin() + 8, r.begin() );\n\n    return aes_le( k, r );\n}\n\nBOOST_AUTO_TEST_CASE( test_s1 )\n{\n    static const uint128_t k = {\n        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00\n    };\n\n    // r1 = 0x000F0E0D0C0B0A091122334455667788\n    static const uint128_t r1 = {\n        0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11,\n        0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x00\n    };\n\n    // r2 = 0x010203040506070899AABBCCDDEEFF00\n    static const uint128_t r2 = {\n        0x00, 0xFF, 0xEE, 0xDD, 0xCC, 0xBB, 0xAA, 0x99,\n        0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01\n    };\n\n    // 0x9a1fe1f0e8b0f49b5b4216ae796da062\n    static const uint128_t expected = {\n        0x62, 0xa0, 0x6d, 0x79, 0xae, 0x16, 0x42, 0x5b,\n        0x9b, 0xf4, 0xb0, 0xe8, 0xf0, 0xe1, 0x1f, 0x9a\n    };\n\n    check_equal( s1( k, r1, r2 ), expected );\n}\n\nBOOST_AUTO_TEST_CASE( check_short_term_key )\n{\n    static const uint128_t k = {\n        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00\n    };\n\n    check_equal( s1( k, peripheral_random_value, central_random_value ), short_term_key );\n}\n\nstatic uint128_t add_to_mac( uint128_t key, uint128_t mac, uint128_t block )\n{\n    return aes( key, xor_( mac, block ) );\n}\n\nstatic uint32_t ccm(uint128_t key, uint64_t counter, bool sent_by_central, uint64_t iv, const uint8_t* input_begin, const uint8_t* input_end, uint8_t* output )\n{\n\n    static const std::size_t  block_size = 128 / 8;\n           const std::size_t  message_length = std::distance( input_begin, input_end );\n\n    assert( message_length > 2 );\n    assert( message_length < 256 + 2 );\n\n    uint128_t b_0 = {\n        0x49,                                           // Flags as per the CCM specification\n        static_cast< std::uint8_t >( counter ),         // Octet0 (LSO) of packetCounter\n        static_cast< std::uint8_t >( counter >> 8 ),    // Octet1 of packetCounter\n        static_cast< std::uint8_t >( counter >> 16 ),   // Octet2 of packetCounter\n        static_cast< std::uint8_t >( counter >> 24 ),   // Octet3 of packetCounter\n        static_cast< std::uint8_t >( counter >> 32 |    // Bit 6 – Bit 0: Octet4 (7 most significant bits of packetCounter, with Bit 6 being the most significant bit)\n            ( sent_by_central ? 0x80 : 0x00 ) ),         // Bit7:directionBit\n        static_cast< std::uint8_t >( iv ),              // Octet0 (LSO) of IV\n        static_cast< std::uint8_t >( iv >> 8 ),         // Octet1 of IV\n        static_cast< std::uint8_t >( iv >> 16 ),        // Octet2 of IV\n        static_cast< std::uint8_t >( iv >> 24 ),        // Octet3 of IV\n        static_cast< std::uint8_t >( iv >> 32 ),        // Octet4 of IV\n        static_cast< std::uint8_t >( iv >> 40 ),        // Octet5 of IV\n        static_cast< std::uint8_t >( iv >> 48 ),        // Octet6 of IV\n        static_cast< std::uint8_t >( iv >> 56 ),        // Octet7 of IV\n        0x00,                                           // The most significant octet of the length of the payload\n        static_cast< std::uint8_t >( message_length - 2 ) // The least significant octet of the length of the payload\n    };\n\n    const auto x1 = aes( key, b_0 );\n\n    uint128_t b_1 = {\n        0x00,                   // The most significant octet of the length of the additional authenticated data\n        0x01,                   // The least significant octet of the length of the additional authenticated data\n        static_cast< std::uint8_t >( *input_begin & 0x03 ),    // The data channel PDU header’s first octet with NESN, SN and MD bits masked to 0\n                                // aka LLID\n    };\n\n    uint128_t mac = add_to_mac( key, x1, b_1 );\n\n    // move input from header to payload\n    input_begin += 2;\n\n    for ( auto begin = input_begin; begin != input_end; )\n    {\n        uint128_t block = { 0 };\n        const std::size_t count = std::min< std::size_t >( std::distance( begin, input_end ), block_size );\n\n        std::copy( begin, begin + count, &block[ 0 ] );\n        mac = add_to_mac( key, mac, block );\n\n        begin += count;\n    }\n\n    // now start entcryption b_0 is equal to A_i when setting flags and i\n    // flag\n    b_0[ 0 ]  = 0x01;\n    b_0[ 15 ] = 0;    // i = 0\n\n    const auto s_0 = aes( key, b_0 );\n\n    mac = xor_( mac, s_0 );\n\n    for ( auto begin = input_begin; begin != input_end; )\n    {\n        ++b_0[ 15 ];\n        const auto s_n = aes( key, b_0 );\n\n        const std::size_t count = std::min< std::size_t >( std::distance( begin, input_end ), block_size );\n\n        uint128_t block;\n        std::copy( begin, begin + count, &block[ 0 ] );\n        block = xor_( block, s_n );\n\n        std::copy( &block[ 0 ], &block[ count ], output );\n\n        output += count;\n        begin  += count;\n    }\n\n    return\n        static_cast< std::uint32_t >( mac[ 3 ] )\n      | static_cast< std::uint32_t >( mac[ 2 ] ) << 8\n      | static_cast< std::uint32_t >( mac[ 1 ] ) << 16\n      | static_cast< std::uint32_t >( mac[ 0 ] ) << 24;\n}\n\n/*\nBOOST_AUTO_TEST_CASE( test_sdk )\n{\n    static const uint128_t ltk = {\n        0x42, 0xc6, 0x06, 0x98, 0x85, 0xe4, 0x94, 0xeb,\n        0xa3, 0xed, 0x19, 0x93, 0xb7, 0x85, 0xd4, 0x99\n    };\n\n    static const uint128_t skd = {\n        0xf4, 0x1e, 0x34, 0x80, 0x5b, 0x2e, 0x37, 0x6c,\n        0x52, 0xf5, 0x07, 0xf8, 0x64, 0xbd, 0x43, 0xca\n    };\n\n    static const uint128_t stk = {\n        0xc1, 0x91, 0x63, 0xa5, 0xc6, 0x5f, 0x8e, 0x3f,\n        0x9b, 0x73, 0xed, 0xdf, 0x17, 0x4c, 0x8c, 0x34\n    };\n\n    check_equal( aes( ltk, skd ), stk );\n}\n*/\nBOOST_AUTO_TEST_CASE( test_ccm )\n{\n    static const uint128_t session_key = {\n        0x99, 0xAD, 0x1B, 0x52, 0x26, 0xA3, 0x7E, 0x3E,\n        0x05, 0x8E, 0x3B, 0x8E, 0x27, 0xC2, 0xC6, 0x66\n    };\n\n    static const uint64_t iv  = 0xDEAFBABEBADCAB24;\n    static const uint32_t mic = 0xCDA7F448;\n\n    static const uint8_t input[]        = { 0xf, 0x01, 0x06 };\n    static       uint8_t output[ 1 ]    = { 0 };\n    static const uint8_t expected[ 1 ]  = { 0x9f };\n\n    const std::uint32_t calc_mic = ccm( session_key, 0, true, iv, std::begin(input), std::end(input), std::begin(output) );\n\n    BOOST_CHECK_EQUAL( calc_mic, mic );\n    BOOST_CHECK_EQUAL_COLLECTIONS( std::begin(output), std::end(output), std::begin(expected), std::end(expected) );\n}\n\n/*\nBOOST_AUTO_TEST_CASE( test_ccm_with_real_data )\n{\n    static const uint128_t key = {\n        0xc1, 0x91, 0x63, 0xa5, 0xc6, 0x5f, 0x8e, 0x3f,\n        0x9b, 0x73, 0xed, 0xdf, 0x17, 0x4c, 0x8c, 0x34\n    };\n\n    uint64_t iv  = 0x2656ace7e969a980;\n    uint32_t mic = 0x712c7a1a;\n\n    static const uint8_t input[] = { 0xf, 0x1, 0x06 };\n    static       uint8_t output[20] = {0};\n\n    const std::uint32_t calc_mic = ccm( key, 0, true, iv, std::begin(input), std::end(input), std::begin(output) );\n\n    BOOST_CHECK_EQUAL( calc_mic, mic );\n}\n*/"
  },
  {
    "path": "tests/security_manager/io_capabilities_tests.cpp",
    "content": "#define BOOST_TEST_MODULE\n#include <boost/test/included/unit_test.hpp>\n\n#include <bluetoe/io_capabilities.hpp>\n\nBOOST_AUTO_TEST_CASE( by_default_no_input_no_output )\n{\n    using capa = bluetoe::details::io_capabilities_matrix<>;\n    BOOST_CHECK( capa::get_io_capabilities() == bluetoe::details::io_capabilities::no_input_no_output );\n}\n\nBOOST_AUTO_TEST_CASE( explicitly_state_no_output )\n{\n    using capa = bluetoe::details::io_capabilities_matrix< bluetoe::pairing_no_output >;\n    BOOST_CHECK( capa::get_io_capabilities() == bluetoe::details::io_capabilities::no_input_no_output );\n}\n\nBOOST_AUTO_TEST_CASE( explicitly_state_no_input )\n{\n    using capa = bluetoe::details::io_capabilities_matrix< bluetoe::pairing_no_input >;\n    BOOST_CHECK( capa::get_io_capabilities() == bluetoe::details::io_capabilities::no_input_no_output );\n}\n\nstruct pairing_yes_no_handler_t\n{\n} pairing_yes_no_handler;\n\nBOOST_AUTO_TEST_CASE( no_output_yes_no_input )\n{\n    using capa = bluetoe::details::io_capabilities_matrix< bluetoe::pairing_yes_no< pairing_yes_no_handler_t, pairing_yes_no_handler > >;\n    BOOST_CHECK( capa::get_io_capabilities() == bluetoe::details::io_capabilities::no_input_no_output );\n}\n\nstruct pairing_keyboard_handler_t\n{\n\n} pairing_keyboard_handler;\n\nBOOST_AUTO_TEST_CASE( no_output_keyboard_input )\n{\n    using capa = bluetoe::details::io_capabilities_matrix<\n        bluetoe::pairing_keyboard< pairing_keyboard_handler_t, pairing_keyboard_handler > >;\n\n    BOOST_CHECK( capa::get_io_capabilities() == bluetoe::details::io_capabilities::keyboard_only );\n}\n\nstruct pairing_numeric_output_handler_t\n{\n    void sm_pairing_numeric_output( int pass_key )\n    {\n        displayed = pass_key;\n    }\n\n    int displayed;\n} pairing_numeric_output_handler;\n\nBOOST_AUTO_TEST_CASE( Numeric_output__No_input )\n{\n    using capa = bluetoe::details::io_capabilities_matrix<\n        bluetoe::pairing_numeric_output< pairing_numeric_output_handler_t, pairing_numeric_output_handler > >;\n\n    BOOST_CHECK( capa::get_io_capabilities() == bluetoe::details::io_capabilities::display_only );\n}\n\nBOOST_AUTO_TEST_CASE( Numeric_output__Yes_No_input )\n{\n    using capa = bluetoe::details::io_capabilities_matrix<\n        bluetoe::pairing_numeric_output< pairing_numeric_output_handler_t, pairing_numeric_output_handler >,\n        bluetoe::pairing_yes_no< pairing_yes_no_handler_t, pairing_yes_no_handler > >;\n\n    BOOST_CHECK( capa::get_io_capabilities() == bluetoe::details::io_capabilities::display_yes_no );\n}\n\nBOOST_AUTO_TEST_CASE( Numeric_output__keyboard_input )\n{\n    using capa = bluetoe::details::io_capabilities_matrix<\n        bluetoe::pairing_numeric_output< pairing_numeric_output_handler_t, pairing_numeric_output_handler >,\n        bluetoe::pairing_keyboard< pairing_keyboard_handler_t, pairing_keyboard_handler > >;\n\n    BOOST_CHECK( capa::get_io_capabilities() == bluetoe::details::io_capabilities::keyboard_display );\n}\n\nBOOST_AUTO_TEST_CASE( legacy_Display_Only_Pairing_Algorithm )\n{\n    using namespace bluetoe::details;\n\n    using capa = io_capabilities_matrix<\n        bluetoe::pairing_numeric_output< pairing_numeric_output_handler_t, pairing_numeric_output_handler > >;\n\n    BOOST_CHECK( capa::select_legacy_pairing_algorithm( io_capabilities::display_only ) == legacy_pairing_algorithm::just_works );\n    BOOST_CHECK( capa::select_legacy_pairing_algorithm( io_capabilities::display_yes_no ) == legacy_pairing_algorithm::just_works );\n    BOOST_CHECK( capa::select_legacy_pairing_algorithm( io_capabilities::keyboard_only ) == legacy_pairing_algorithm::passkey_entry_display );\n    BOOST_CHECK( capa::select_legacy_pairing_algorithm( io_capabilities::no_input_no_output ) == legacy_pairing_algorithm::just_works );\n    BOOST_CHECK( capa::select_legacy_pairing_algorithm( io_capabilities::keyboard_display ) == legacy_pairing_algorithm::passkey_entry_display );\n}\n\nBOOST_AUTO_TEST_CASE( lesc_Display_Only_Pairing_Algorithm )\n{\n    using namespace bluetoe::details;\n\n    using capa = io_capabilities_matrix<\n        bluetoe::pairing_numeric_output< pairing_numeric_output_handler_t, pairing_numeric_output_handler > >;\n\n    BOOST_CHECK( capa::select_lesc_pairing_algorithm( io_capabilities::display_only ) == lesc_pairing_algorithm::just_works );\n    BOOST_CHECK( capa::select_lesc_pairing_algorithm( io_capabilities::display_yes_no ) == lesc_pairing_algorithm::just_works );\n    BOOST_CHECK( capa::select_lesc_pairing_algorithm( io_capabilities::keyboard_only ) == lesc_pairing_algorithm::passkey_entry_display );\n    BOOST_CHECK( capa::select_lesc_pairing_algorithm( io_capabilities::no_input_no_output ) == lesc_pairing_algorithm::just_works );\n    BOOST_CHECK( capa::select_lesc_pairing_algorithm( io_capabilities::keyboard_display ) == lesc_pairing_algorithm::passkey_entry_display );\n}\n\nBOOST_AUTO_TEST_CASE( legacy_Display_Yes_No_Pairing_Algorithm )\n{\n    using namespace bluetoe::details;\n\n    using capa = io_capabilities_matrix<\n        bluetoe::pairing_numeric_output< pairing_numeric_output_handler_t, pairing_numeric_output_handler >,\n        bluetoe::pairing_yes_no< pairing_yes_no_handler_t, pairing_yes_no_handler > >;\n\n    BOOST_CHECK( capa::select_legacy_pairing_algorithm( io_capabilities::display_only ) == legacy_pairing_algorithm::just_works );\n    BOOST_CHECK( capa::select_legacy_pairing_algorithm( io_capabilities::display_yes_no ) == legacy_pairing_algorithm::just_works );\n    BOOST_CHECK( capa::select_legacy_pairing_algorithm( io_capabilities::keyboard_only ) == legacy_pairing_algorithm::passkey_entry_display );\n    BOOST_CHECK( capa::select_legacy_pairing_algorithm( io_capabilities::no_input_no_output ) == legacy_pairing_algorithm::just_works );\n    BOOST_CHECK( capa::select_legacy_pairing_algorithm( io_capabilities::keyboard_display ) == legacy_pairing_algorithm::passkey_entry_display );\n}\n\nBOOST_AUTO_TEST_CASE( lesc_Display_Yes_No_Pairing_Algorithm )\n{\n    using namespace bluetoe::details;\n\n    using capa = io_capabilities_matrix<\n        bluetoe::pairing_numeric_output< pairing_numeric_output_handler_t, pairing_numeric_output_handler >,\n        bluetoe::pairing_yes_no< pairing_yes_no_handler_t, pairing_yes_no_handler > >;\n\n    BOOST_CHECK( capa::select_lesc_pairing_algorithm( io_capabilities::display_only ) == lesc_pairing_algorithm::just_works );\n    BOOST_CHECK( capa::select_lesc_pairing_algorithm( io_capabilities::display_yes_no ) == lesc_pairing_algorithm::numeric_comparison );\n    BOOST_CHECK( capa::select_lesc_pairing_algorithm( io_capabilities::keyboard_only ) == lesc_pairing_algorithm::passkey_entry_display );\n    BOOST_CHECK( capa::select_lesc_pairing_algorithm( io_capabilities::no_input_no_output ) == lesc_pairing_algorithm::just_works );\n    BOOST_CHECK( capa::select_lesc_pairing_algorithm( io_capabilities::keyboard_display ) == lesc_pairing_algorithm::numeric_comparison );\n}\n\nBOOST_AUTO_TEST_CASE( legacy_Keyboard_Only_Pairing_Algorithm )\n{\n    using namespace bluetoe::details;\n\n    using capa = io_capabilities_matrix<\n        bluetoe::pairing_keyboard< pairing_keyboard_handler_t, pairing_keyboard_handler > >;\n\n    BOOST_CHECK( capa::select_legacy_pairing_algorithm( io_capabilities::display_only ) == legacy_pairing_algorithm::passkey_entry_input );\n    BOOST_CHECK( capa::select_legacy_pairing_algorithm( io_capabilities::display_yes_no ) == legacy_pairing_algorithm::passkey_entry_input );\n    BOOST_CHECK( capa::select_legacy_pairing_algorithm( io_capabilities::keyboard_only ) == legacy_pairing_algorithm::passkey_entry_input );\n    BOOST_CHECK( capa::select_legacy_pairing_algorithm( io_capabilities::no_input_no_output ) == legacy_pairing_algorithm::just_works );\n    BOOST_CHECK( capa::select_legacy_pairing_algorithm( io_capabilities::keyboard_display ) == legacy_pairing_algorithm::passkey_entry_input );\n}\n\nBOOST_AUTO_TEST_CASE( lesc_Keyboard_Only_Pairing_Algorithm )\n{\n    using namespace bluetoe::details;\n\n    using capa = io_capabilities_matrix<\n        bluetoe::pairing_keyboard< pairing_keyboard_handler_t, pairing_keyboard_handler > >;\n\n    BOOST_CHECK( capa::select_lesc_pairing_algorithm( io_capabilities::display_only ) == lesc_pairing_algorithm::passkey_entry_input );\n    BOOST_CHECK( capa::select_lesc_pairing_algorithm( io_capabilities::display_yes_no ) == lesc_pairing_algorithm::passkey_entry_input );\n    BOOST_CHECK( capa::select_lesc_pairing_algorithm( io_capabilities::keyboard_only ) == lesc_pairing_algorithm::passkey_entry_input );\n    BOOST_CHECK( capa::select_lesc_pairing_algorithm( io_capabilities::no_input_no_output ) == lesc_pairing_algorithm::just_works );\n    BOOST_CHECK( capa::select_lesc_pairing_algorithm( io_capabilities::keyboard_display ) == lesc_pairing_algorithm::passkey_entry_input );\n}\n\nBOOST_AUTO_TEST_CASE( legacy_No_Input_No_Output_Pairing_Algorithm )\n{\n    using namespace bluetoe::details;\n\n    using capa = io_capabilities_matrix<>;\n\n    BOOST_CHECK( capa::select_legacy_pairing_algorithm( io_capabilities::display_only ) == legacy_pairing_algorithm::just_works );\n    BOOST_CHECK( capa::select_legacy_pairing_algorithm( io_capabilities::display_yes_no ) == legacy_pairing_algorithm::just_works );\n    BOOST_CHECK( capa::select_legacy_pairing_algorithm( io_capabilities::keyboard_only ) == legacy_pairing_algorithm::just_works );\n    BOOST_CHECK( capa::select_legacy_pairing_algorithm( io_capabilities::no_input_no_output ) == legacy_pairing_algorithm::just_works );\n    BOOST_CHECK( capa::select_legacy_pairing_algorithm( io_capabilities::keyboard_display ) == legacy_pairing_algorithm::just_works );\n}\n\nBOOST_AUTO_TEST_CASE( lesc_No_Input_No_Output_Pairing_Algorithm )\n{\n    using namespace bluetoe::details;\n\n    using capa = io_capabilities_matrix<>;\n\n    BOOST_CHECK( capa::select_lesc_pairing_algorithm( io_capabilities::display_only ) == lesc_pairing_algorithm::just_works );\n    BOOST_CHECK( capa::select_lesc_pairing_algorithm( io_capabilities::display_yes_no ) == lesc_pairing_algorithm::just_works );\n    BOOST_CHECK( capa::select_lesc_pairing_algorithm( io_capabilities::keyboard_only ) == lesc_pairing_algorithm::just_works );\n    BOOST_CHECK( capa::select_lesc_pairing_algorithm( io_capabilities::no_input_no_output ) == lesc_pairing_algorithm::just_works );\n    BOOST_CHECK( capa::select_lesc_pairing_algorithm( io_capabilities::keyboard_display ) == lesc_pairing_algorithm::just_works );\n}\n\nBOOST_AUTO_TEST_CASE( legacy_Keyboard_Display_Pairing_Algorithm )\n{\n    using namespace bluetoe::details;\n\n    using capa = io_capabilities_matrix<\n        bluetoe::pairing_keyboard< pairing_keyboard_handler_t, pairing_keyboard_handler >,\n        bluetoe::pairing_numeric_output< pairing_numeric_output_handler_t, pairing_numeric_output_handler > >;\n\n    BOOST_CHECK( capa::select_legacy_pairing_algorithm( io_capabilities::display_only ) == legacy_pairing_algorithm::passkey_entry_input );\n    BOOST_CHECK( capa::select_legacy_pairing_algorithm( io_capabilities::display_yes_no ) == legacy_pairing_algorithm::passkey_entry_input );\n    BOOST_CHECK( capa::select_legacy_pairing_algorithm( io_capabilities::keyboard_only ) == legacy_pairing_algorithm::passkey_entry_display );\n    BOOST_CHECK( capa::select_legacy_pairing_algorithm( io_capabilities::no_input_no_output ) == legacy_pairing_algorithm::just_works );\n    BOOST_CHECK( capa::select_legacy_pairing_algorithm( io_capabilities::keyboard_display ) == legacy_pairing_algorithm::passkey_entry_input );\n}\n\nBOOST_AUTO_TEST_CASE( lesc_Keyboard_Display_Pairing_Algorithm )\n{\n    using namespace bluetoe::details;\n\n    using capa = io_capabilities_matrix<\n        bluetoe::pairing_keyboard< pairing_keyboard_handler_t, pairing_keyboard_handler >,\n        bluetoe::pairing_numeric_output< pairing_numeric_output_handler_t, pairing_numeric_output_handler > >;\n\n    BOOST_CHECK( capa::select_lesc_pairing_algorithm( io_capabilities::display_only ) == lesc_pairing_algorithm::passkey_entry_input );\n    BOOST_CHECK( capa::select_lesc_pairing_algorithm( io_capabilities::display_yes_no ) == lesc_pairing_algorithm::numeric_comparison );\n    BOOST_CHECK( capa::select_lesc_pairing_algorithm( io_capabilities::keyboard_only ) == lesc_pairing_algorithm::passkey_entry_display );\n    BOOST_CHECK( capa::select_lesc_pairing_algorithm( io_capabilities::no_input_no_output ) == lesc_pairing_algorithm::just_works );\n    BOOST_CHECK( capa::select_lesc_pairing_algorithm( io_capabilities::keyboard_display ) == lesc_pairing_algorithm::numeric_comparison );\n}\n\nBOOST_AUTO_TEST_CASE( lesc_numeric_comparison_display )\n{\n    pairing_numeric_output_handler.displayed = ~0;\n\n    using capa = bluetoe::details::io_capabilities_matrix<\n        bluetoe::pairing_yes_no< pairing_yes_no_handler_t, pairing_yes_no_handler >,\n        bluetoe::pairing_numeric_output< pairing_numeric_output_handler_t, pairing_numeric_output_handler > >;\n\n    static const std::array< std::uint8_t, 32 > pka = {{\n        0xe6, 0x9d, 0x35, 0x0e,\n        0x48, 0x01, 0x03, 0xcc,\n        0xdb, 0xfd, 0xf4, 0xac,\n        0x11, 0x91, 0xf4, 0xef,\n        0xb9, 0xa5, 0xf9, 0xe9,\n        0xa7, 0x83, 0x2c, 0x5e,\n        0x2c, 0xbe, 0x97, 0xf2,\n        0xd2, 0x03, 0xb0, 0x20\n    }};\n\n    static const std::array< std::uint8_t, 32 > pkb = {{\n        0xfd, 0xc5, 0x7f, 0xf4,\n        0x49, 0xdd, 0x4f, 0x6b,\n        0xfb, 0x7c, 0x9d, 0xf1,\n        0xc2, 0x9a, 0xcb, 0x59,\n        0x2a, 0xe7, 0xd4, 0xee,\n        0xfb, 0xfc, 0x0a, 0x90,\n        0x9a, 0xbb, 0xf6, 0x32,\n        0x3d, 0x8b, 0x18, 0x55\n    }};\n\n    static const std::array< std::uint8_t, 16 > na = {{\n        0xab, 0xae, 0x2b, 0x71,\n        0xec, 0xb2, 0xff, 0xff,\n        0x3e, 0x73, 0x77, 0xd1,\n        0x54, 0x84, 0xcb, 0xd5\n    }};\n\n    static const std::array< std::uint8_t, 16 > nb = {{\n        0xcf, 0xc4, 0x3d, 0xff,\n        0xf7, 0x83, 0x65, 0x21,\n        0x6e, 0x5f, 0xa7, 0x25,\n        0xcc, 0xe7, 0xe8, 0xa6\n    }};\n\n    struct state_t {\n        const std::array< std::uint8_t, 16 >& local_nonce() const\n        {\n            return nb;\n        }\n\n        const std::array< std::uint8_t, 16 >& remote_nonce() const\n        {\n            return na;\n        }\n\n        const std::uint8_t* local_public_key_x() const\n        {\n            return pkb.data();\n        }\n\n        const std::uint8_t* remote_public_key_x() const\n        {\n            return pka.data();\n        }\n    } state;\n\n    struct functions_t {\n        std::uint32_t g2( const std::uint8_t* u, const std::uint8_t* v, const std::array< std::uint8_t, 16 >& x, const std::array< std::uint8_t, 16 >& y )\n        {\n            BOOST_CHECK_EQUAL_COLLECTIONS( u, u + 32, pka.begin(), pka.end() );\n            BOOST_CHECK_EQUAL_COLLECTIONS( v, v + 32, pkb.begin(), pkb.end() );\n            BOOST_CHECK_EQUAL_COLLECTIONS( x.begin(), x.end(), na.begin(), na.end() );\n            BOOST_CHECK_EQUAL_COLLECTIONS( y.begin(), y.end(), nb.begin(), nb.end() );\n\n            return 0x22334455;\n        }\n\n    } functions;\n\n    capa::sm_pairing_numeric_compare_output( state, functions );\n    BOOST_CHECK_EQUAL( pairing_numeric_output_handler.displayed, 0x22334455 );\n}\n"
  },
  {
    "path": "tests/security_manager/key_distribution_tests.cpp",
    "content": "#define BOOST_TEST_MODULE\n#include <boost/test/included/unit_test.hpp>\n\n#include <bluetoe/security_manager.hpp>\n\n#include \"test_sm.hpp\"\n\nBOOST_AUTO_TEST_CASE_TEMPLATE( no_distribution_over_unsecure_connection,  Manager, test::legacy_managers )\n{\n    test::legacy_pairing_random_exchanged< Manager > fixture;\n\n    bluetoe::details::link_state link;\n    BOOST_CHECK( !fixture.connection_data().outgoing_security_manager_data_available( link ) );\n}\n\nBOOST_AUTO_TEST_CASE_TEMPLATE( no_distribution_when_in_wrong_state, Manager, test::legacy_managers )\n{\n    test::legacy_pairing_confirm_exchanged< Manager > fixture;\n\n    bluetoe::details::link_state link;\n    BOOST_CHECK( !fixture.connection_data().outgoing_security_manager_data_available( link ) );\n}\n"
  },
  {
    "path": "tests/security_manager/pairing_confirm_tests.cpp",
    "content": "#define BOOST_TEST_MODULE\n#include <boost/test/included/unit_test.hpp>\n\n#include <bluetoe/security_manager.hpp>\n\n#include \"test_sm.hpp\"\n\nBOOST_AUTO_TEST_CASE_TEMPLATE( invalid_state, Manager, test::legacy_managers )\n{\n    test::security_manager_base< Manager, test::all_security_functions, 65 > fixture;\n\n    fixture.expected(\n        {\n            0x03,                   // Pairing Confirm\n            0x00, 0x00, 0x00, 0x00,\n            0x00, 0x00, 0x00, 0x00,\n            0x00, 0x00, 0x00, 0x00,\n            0x00, 0x00, 0x00, 0x00,\n        },\n        {\n            0x05,                   // Pairing Failed\n            0x08                    // Unspecified Reason\n        }\n    );\n}\n\nBOOST_AUTO_TEST_CASE_TEMPLATE( invalid_size, Manager, test::legacy_managers )\n{\n    test::legacy_pairing_features_exchanged< Manager > fixture;\n\n    fixture.expected(\n        {\n            0x03,                   // Pairing Confirm\n        },\n        {\n            0x05,                   // Pairing Failed\n            0x0A                    // Invalid Parameters\n        }\n    );\n}\n\nBOOST_AUTO_TEST_CASE_TEMPLATE( invalid_size_II, Manager, test::legacy_managers )\n{\n    test::legacy_pairing_features_exchanged< Manager > fixture;\n\n    fixture.expected(\n        {\n            0x03,                   // Pairing Confirm\n            0x00, 0x00, 0x00, 0x00,\n            0x00, 0x00, 0x00, 0x00,\n            0x00, 0x00, 0x00, 0x00,\n            0x00, 0x00, 0x00, 0x00,\n            0x00\n        },\n        {\n            0x05,                   // Pairing Failed\n            0x0A                    // Invalid Parameters\n        }\n    );\n}\n\n/**\n * The original test vector is:\n *\n * 8-bit iat’ is 0x01\n * 8-bit rat’ is 0x00\n * 56-bit preq is 0x07071000000101\n * 56 bit pres is 0x05000800000302\n * p1 is 0x05000800000302070710000001010001\n * 48-bit ia is 0xA1A2A3A4A5A6\n * 48-bit ra is 0xB1B2B3B4B5B6\n * p2 is 0x00000000A1A2A3A4A5A6B1B2B3B4B5B6\n * 128-bit k is 0x00000000000000000000000000000000\n * 128-bit value r is 0x5783D52156AD6F0E6388274EC6702EE0\n * 128-bit output from the c1 function is 0x1e1e3fef878988ead2a74dc5bef13b86\n *\n * changed:\n * 56 bit pres is 0x00001000000302\n */\nBOOST_FIXTURE_TEST_CASE( correct_paring_request, test::legacy_security_manager<> )\n{\n    expected(\n        {\n            0x01,                   // Pairing Request\n            0x01, 0x00, 0x00, 0x10, 0x07, 0x07\n        },\n        {\n            0x02,                   // Pairing Response\n            0x03, 0x00, 0x00, 0x10, 0x00, 0x00\n        }\n    );\n\n    expected(\n        {\n            0x03,                   // Pairing Confirm\n            0x00, 0x00, 0x00, 0x00,\n            0x00, 0x00, 0x00, 0x00,\n            0x00, 0x00, 0x00, 0x00,\n            0x00, 0x00, 0x00, 0x00\n        },\n        {\n            0x03,                   // Pairing Confirm\n            0xe2, 0x16, 0xb5, 0x44, // Confirm Value\n            0x96, 0xa2, 0xe7, 0x90,\n            0x53, 0xb2, 0x31, 0x06,\n            0xc9, 0xdd, 0xd4, 0xf8\n        }\n    );\n}\n\n/**\n * The original test vector is:\n *\n * 8-bit iat’ is 0x01\n * 8-bit rat’ is 0x00\n * 56-bit preq is 0x07071000000101\n * 56 bit pres is 0x05000800000302\n * p1 is 0x05000800000302070710000001010001\n * 48-bit ia is 0xA1A2A3A4A5A6\n * 48-bit ra is 0xB1B2B3B4B5B6\n * p2 is 0x00000000A1A2A3A4A5A6B1B2B3B4B5B6\n * 128-bit k is 0x00000000000000000000000000000000\n * 128-bit value r is 0x5783D52156AD6F0E6388274EC6702EE0\n * 128-bit output from the c1 function is 0x1e1e3fef878988ead2a74dc5bef13b86\n *\n * changed:\n * 56 bit pres is 0x00001008000302\n */\nBOOST_FIXTURE_TEST_CASE( correct_paring_request_combined_manager, test::security_manager<> )\n{\n    expected(\n        {\n            0x01,                   // Pairing Request\n            0x01, 0x00, 0x00, 0x10, 0x07, 0x07\n        },\n        {\n            0x02,                   // Pairing Response\n            0x03, 0x00, 0x08, 0x10, 0x00, 0x00\n        }\n    );\n\n    expected(\n        {\n            0x03,                   // Pairing Confirm\n            0x00, 0x00, 0x00, 0x00,\n            0x00, 0x00, 0x00, 0x00,\n            0x00, 0x00, 0x00, 0x00,\n            0x00, 0x00, 0x00, 0x00\n        },\n        {\n            0x03,                   // Pairing Confirm\n            0xc9, 0x16, 0xcc, 0xf3, // Confirm Value\n            0xf2, 0xb1, 0x6d, 0x8f,\n            0xbb, 0x6d, 0x71, 0x4b,\n            0x9c, 0xa7, 0xd8, 0xa8\n        }\n    );\n}\n"
  },
  {
    "path": "tests/security_manager/pairing_random_tests.cpp",
    "content": "#define BOOST_TEST_MODULE\n#include <boost/test/included/unit_test.hpp>\n\n#include <bluetoe/security_manager.hpp>\n\n#include \"test_sm.hpp\"\n\nBOOST_AUTO_TEST_CASE_TEMPLATE( wrong_state, Manager, test::legacy_managers )\n{\n    test::legacy_pairing_features_exchanged< Manager > fixture;\n\n    fixture.expected(\n        {\n            0x04,                   // opcode\n            0x00, 0x01, 0x02, 0x03,\n            0x00, 0x01, 0x02, 0x03,\n            0x00, 0x01, 0x02, 0x03,\n            0x00, 0x01, 0x02, 0x03\n        },\n        {\n            0x05,                   // Pairing Failed\n            0x08                    // Unspecified Reason\n        }\n    );\n}\n\nBOOST_AUTO_TEST_CASE_TEMPLATE( wrong_size, Manager, test::legacy_managers )\n{\n    test::legacy_pairing_confirm_exchanged< Manager > fixture;\n\n    fixture.expected(\n        {\n            0x04,                   // opcode\n            0x00, 0x01, 0x02, 0x03,\n            0x00, 0x01, 0x02, 0x03,\n            0x00, 0x01, 0x02, 0x03,\n            0x00, 0x01, 0x02\n        },\n        {\n            0x05,           // Pairing Failed\n            0x0A            // Invalid Parameters\n        }\n    );\n}\n\nBOOST_AUTO_TEST_CASE_TEMPLATE( wrong_size_II, Manager, test::legacy_managers )\n{\n    test::legacy_pairing_confirm_exchanged< Manager > fixture;\n\n    fixture.expected(\n        {\n            0x04,                   // opcode\n            0x00, 0x01, 0x02, 0x03,\n            0x00, 0x01, 0x02, 0x03,\n            0x00, 0x01, 0x02, 0x03,\n            0x00, 0x01, 0x02, 0x03,\n            0xff\n        },\n        {\n            0x05,           // Pairing Failed\n            0x0A            // Invalid Parameters\n        }\n    );\n}\n\nBOOST_AUTO_TEST_CASE_TEMPLATE( incorrect_confirm_value, Manager, test::legacy_managers )\n{\n    test::legacy_pairing_confirm_exchanged< Manager > fixture;\n\n    fixture.expected(\n        {\n            0x04,                   // opcode\n            0xE0, 0x2E, 0x70, 0xC6,\n            0x4E, 0x27, 0x88, 0x63,\n            0x0E, 0x6F, 0xAD, 0x56,\n            0x21, 0xD5, 0x83, 0x56\n        },\n        {\n            0x05,           // Pairing Failed\n            0x04            // Confirm Value Failed\n        }\n    );\n}\n\nBOOST_AUTO_TEST_CASE_TEMPLATE( correct_confirm_value, Manager, test::legacy_managers )\n{\n    test::legacy_pairing_confirm_exchanged< Manager > fixture;\n\n    fixture.expected(\n        {\n            0x04,                   // opcode\n            0xE0, 0x2E, 0x70, 0xC6,\n            0x4E, 0x27, 0x88, 0x63,\n            0x0E, 0x6F, 0xAD, 0x56,\n            0x21, 0xD5, 0x83, 0x57\n        },\n        {\n            0x04,                   // opcode\n            0xE0, 0x2E, 0x70, 0xC6,\n            0x4E, 0x27, 0x88, 0x63,\n            0x0E, 0x6F, 0xAD, 0x56,\n            0x21, 0xD5, 0x83, 0x57\n        }\n    );\n}\n"
  },
  {
    "path": "tests/security_manager/pairing_request_tests.cpp",
    "content": "#define BOOST_TEST_MODULE\n#include <boost/test/included/unit_test.hpp>\n\n#include <bluetoe/security_manager.hpp>\n\n#include \"test_sm.hpp\"\n\nusing security_managers_under_test = std::tuple<\n    test::legacy_security_manager<>,\n    test::lesc_security_manager<> >;\n\nBOOST_AUTO_TEST_SUITE( invalid_pairing_requests )\n\n    BOOST_AUTO_TEST_CASE_TEMPLATE( empty_request, Manager, security_managers_under_test )\n    {\n        Manager mng;\n        mng.expected(\n            {\n            },\n            {\n                0x05,           // Pairing Failed\n                0x0A            // Invalid Parameters\n            }\n        );\n    }\n\n    BOOST_AUTO_TEST_CASE_TEMPLATE( invalid_opcode, Manager, security_managers_under_test )\n    {\n        Manager mng;\n        mng.expected(\n            {\n                0x55\n            },\n            {\n                0x05,           // Pairing Failed\n                0x07            // Command Not Supported\n            }\n        );\n    }\n\n    BOOST_AUTO_TEST_CASE_TEMPLATE( no_parameters, Manager, security_managers_under_test )\n    {\n        Manager mng;\n        mng.expected(\n            {\n                0x01            // Pairing Request\n            },\n            {\n                0x05,           // Pairing Failed\n                0x0A            // Invalid Parameters\n            }\n        );\n    }\n\n    BOOST_AUTO_TEST_CASE_TEMPLATE( invalid_IO_Capability, Manager, security_managers_under_test )\n    {\n        Manager mng;\n        mng.expected(\n            {\n                0x01,           // Pairing Request\n                0x05,           // IO Capability RFU\n                0x00,           // OOB data flag (data not present)\n                0x00,           // AuthReq\n                0x10,           // Maximum Encryption Key Size (16)\n                0x00,           // Initiator Key Distribution\n                0x00,           // Responder Key Distribution\n\n            },\n            {\n                0x05,           // Pairing Failed\n                0x0A            // Invalid Parameters\n            }\n        );\n    }\n\n    BOOST_AUTO_TEST_CASE_TEMPLATE( invalid_OOB_data_flag, Manager, security_managers_under_test )\n    {\n        Manager mng;\n        mng.expected(\n            {\n                0x01,           // Pairing Request\n                0x03,           // IO Capability NoInputNoOutput\n                0x02,           // OOB data flag (RFU)\n                0x00,           // AuthReq\n                0x10,           // Maximum Encryption Key Size (16)\n                0x00,           // Initiator Key Distribution\n                0x00,           // Responder Key Distribution\n\n            },\n            {\n                0x05,           // Pairing Failed\n                0x0A            // Invalid Parameters\n            }\n        );\n    }\n\n    BOOST_AUTO_TEST_CASE_TEMPLATE( invalid_Encryption_Key_Size, Manager, security_managers_under_test )\n    {\n        Manager mng;\n        mng.expected(\n            {\n                0x01,           // Pairing Request\n                0x03,           // IO Capability NoInputNoOutput\n                0x00,           // OOB data flag (data not present)\n                0x00,           // AuthReq\n                0x11,           // Maximum Encryption Key Size (17)\n                0x00,           // Initiator Key Distribution\n                0x00,           // Responder Key Distribution\n\n            },\n            {\n                0x05,           // Pairing Failed\n                0x0A            // Invalid Parameters\n            }\n        );\n    }\n\n    BOOST_AUTO_TEST_CASE_TEMPLATE( invalid_Encryption_Key_Size_II, Manager, security_managers_under_test )\n    {\n        Manager mng;\n        mng.expected(\n            {\n                0x01,           // Pairing Request\n                0x03,           // IO Capability NoInputNoOutput\n                0x00,           // OOB data flag (data not present)\n                0x00,           // AuthReq\n                0x06,           // Maximum Encryption Key Size (6)\n                0x00,           // Initiator Key Distribution\n                0x00,           // Responder Key Distribution\n\n            },\n            {\n                0x05,           // Pairing Failed\n                0x0A            // Invalid Parameters\n            }\n        );\n    }\n\n    BOOST_AUTO_TEST_CASE_TEMPLATE( invalid_Initiator_Key_Distribution, Manager, security_managers_under_test )\n    {\n        Manager mng;\n        mng.expected(\n            {\n                0x01,           // Pairing Request\n                0x03,           // IO Capability NoInputNoOutput\n                0x00,           // OOB data flag (data not present)\n                0x00,           // AuthReq\n                0x10,           // Maximum Encryption Key Size (16)\n                0xF0,           // Initiator Key Distribution (RFU)\n                0x00,           // Responder Key Distribution\n\n            },\n            {\n                0x05,           // Pairing Failed\n                0x0A            // Invalid Parameters\n            }\n        );\n    }\n\n    BOOST_AUTO_TEST_CASE_TEMPLATE( invalid_Responder_Key_Distribution, Manager, security_managers_under_test )\n    {\n        Manager mng;\n        mng.expected(\n            {\n                0x01,           // Pairing Request\n                0x03,           // IO Capability NoInputNoOutput\n                0x00,           // OOB data flag (data not present)\n                0x00,           // AuthReq\n                0x10,           // Maximum Encryption Key Size (16)\n                0x00,           // Initiator Key Distribution\n                0xF0,           // Responder Key Distribution (RFU)\n            },\n            {\n                0x05,           // Pairing Failed\n                0x0A            // Invalid Parameters\n            }\n        );\n    }\n\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_CASE_TEMPLATE( not_in_idle_state, Manager, test::legacy_managers )\n{\n    test::legacy_pairing_features_exchanged< Manager > fixture;\n\n    fixture.expected(\n        {\n            0x01,           // Pairing Request\n            0x03,           // IO Capability NoInputNoOutput\n            0x00,           // OOB data flag (data not present)\n            0x00,           // AuthReq\n            0x10,           // Maximum Encryption Key Size (16)\n            0x00,           // Initiator Key Distribution\n            0x00,           // Responder Key Distribution (RFU)\n        },\n        {\n            0x05,           // Pairing Failed\n            0x08            // Unspecified Reason\n        }\n    );\n}\n\nBOOST_FIXTURE_TEST_CASE( legacy_not_supported, test::lesc_security_manager<> )\n{\n    expected(\n        {\n            0x01,           // Pairing Request\n            0x01,           // IO Capability NoInputNoOutput\n            0x00,           // OOB data flag (data not present)\n            0x00,           // AuthReq, SC not set!\n            0x10,           // Maximum Encryption Key Size (16)\n            0x07,           // Initiator Key Distribution\n            0x07,           // Responder Key Distribution (RFU)\n        },\n        {\n            0x05,           // Pairing Failed\n            0x05            // Pairing Not Supported\n        }\n    );\n}\n\nBOOST_AUTO_TEST_SUITE( auth_req_field )\n\nusing legacy_bonding_response = test::legacy_security_manager< 23, bluetoe::enable_bonding >;\n\nBOOST_FIXTURE_TEST_CASE( bonding_flag_in_response, legacy_bonding_response )\n{\n    expected(\n        {\n            0x01,                   // Pairing Request\n            0x01, 0x00, 0x00, 0x10, 0x07, 0x07\n        },\n        {\n            0x02,                   // Pairing Response\n            0x03, 0x00, 0x01, 0x10, 0x00, 0x00\n        }\n    );\n}\n\nusing legacy_mitm_response = test::legacy_security_manager< 23, bluetoe::require_man_in_the_middle_protection >;\n\nBOOST_FIXTURE_TEST_CASE( mitm_flag_in_response, legacy_mitm_response )\n{\n    expected(\n        {\n            0x01,                   // Pairing Request\n            0x01, 0x00, 0x00, 0x10, 0x07, 0x07\n        },\n        {\n            0x02,                   // Pairing Response\n            0x03, 0x00, 0x04, 0x10, 0x00, 0x00\n        }\n    );\n}\n\nusing legacy_keypress_response = test::legacy_security_manager< 23, bluetoe::enable_keypress_notifications >;\n\nBOOST_FIXTURE_TEST_CASE( keypress_flag_in_response, legacy_keypress_response )\n{\n    expected(\n        {\n            0x01,                   // Pairing Request\n            0x01, 0x00, 0x00, 0x10, 0x07, 0x07\n        },\n        {\n            0x02,                   // Pairing Response\n            0x03, 0x00, 0x10, 0x10, 0x00, 0x00\n        }\n    );\n}\n\nusing lesc_bonding_response = test::lesc_security_manager< 65, bluetoe::enable_bonding >;\n\nBOOST_FIXTURE_TEST_CASE( lesc_bonding_flag_in_response, lesc_bonding_response )\n{\n    expected(\n        {\n            0x01,                   // Pairing Request\n            0x01, 0x00, 0x08, 0x10, 0x07, 0x07\n        },\n        {\n            0x02,                   // Pairing Response\n            0x03, 0x00, 0x09, 0x10, 0x00, 0x00\n        }\n    );\n}\n\nusing lesc_mitm_response = test::lesc_security_manager< 65, bluetoe::require_man_in_the_middle_protection >;\n\nBOOST_FIXTURE_TEST_CASE( lesc_mitm_flag_in_response, lesc_mitm_response )\n{\n    expected(\n        {\n            0x01,                   // Pairing Request\n            0x01, 0x00, 0x08, 0x10, 0x07, 0x07\n        },\n        {\n            0x02,                   // Pairing Response\n            0x03, 0x00, 0x0C, 0x10, 0x00, 0x00\n        }\n    );\n}\n\nusing lesc_keypress_response = test::lesc_security_manager< 65, bluetoe::enable_keypress_notifications >;\n\nBOOST_FIXTURE_TEST_CASE( lesc_keypress_flag_in_response, lesc_keypress_response )\n{\n    expected(\n        {\n            0x01,                   // Pairing Request\n            0x01, 0x00, 0x08, 0x10, 0x07, 0x07\n        },\n        {\n            0x02,                   // Pairing Response\n            0x03, 0x00, 0x18, 0x10, 0x00, 0x00\n        }\n    );\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "tests/security_manager/pairing_tests.cpp",
    "content": "#define BOOST_TEST_MODULE\n#include <boost/test/included/unit_test.hpp>\n\n#include \"test_sm.hpp\"\n#include \"test_servers.hpp\"\n#include \"pairing_status_io.hpp\"\n\nstatic const std::initializer_list< std::uint8_t > legacy_pairing_request = {\n    0x01, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00\n};\n\nstatic const std::initializer_list< std::uint8_t > lesc_pairing_request = {\n    0x01, 0x00, 0x00, 0x08, 0x07, 0x00, 0x00\n};\n\nusing no_security_sm = test::security_manager_base< bluetoe::no_security_manager, test::lesc_security_functions, 27 >;\n\nusing legacy_enabled_security_managers = std::tuple<\n    test::legacy_security_manager<>,\n    test::security_manager<> >;\n\nBOOST_FIXTURE_TEST_CASE( no_security_manager_no_pairing, no_security_sm )\n{\n    expected(\n        legacy_pairing_request,\n        {\n            0x05, 0x05\n        }\n    );\n}\n\nBOOST_FIXTURE_TEST_SUITE( legacy_pairing, test::legacy_security_manager<> )\n\n    BOOST_AUTO_TEST_CASE( by_default_no_oob_no_lesc )\n    {\n        expected(\n            legacy_pairing_request,\n            {\n                0x02,   // response\n                0x03,   // NoInputNoOutput\n                0x00,   // OOB Authentication data not present\n                0x00,   // Bonding, MITM = 0, SC = 0, Keypress = 0\n                0x10,   // Maximum Encryption Key Size\n                0x00,   // LinkKey\n                0x00    // LinkKey\n            }\n        );\n    }\n\n    BOOST_AUTO_TEST_CASE( no_lesc_event_when_the_initiater_is_asking_for_it )\n    {\n        expected(\n            lesc_pairing_request,\n            {\n                0x02,   // response\n                0x03,   // NoInputNoOutput\n                0x00,   // OOB Authentication data not present\n                0x00,   // Bonding, MITM = 0, SC = 0, Keypress = 0\n                0x10,   // Maximum Encryption Key Size\n                0x00,   // LinkKey\n                0x00    // LinkKey\n            }\n        );\n    }\n\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_FIXTURE_TEST_SUITE( lesc_pairing_with_lesc_only_security_manager, test::lesc_security_manager<> )\n\n    BOOST_AUTO_TEST_CASE( by_default_no_oob_but_lesc )\n    {\n        expected(\n            lesc_pairing_request,\n            {\n                0x02,   // response\n                0x03,   // NoInputNoOutput\n                0x00,   // OOB Authentication data not present\n                0x08,   // Bonding, MITM = 0, SC = 1, Keypress = 0\n                0x10,   // Maximum Encryption Key Size\n                0x00,   // LinkKey\n                0x00    // LinkKey\n            }\n        );\n    }\n\n    BOOST_AUTO_TEST_CASE( reject_request_without_lesc )\n    {\n        expected(\n            legacy_pairing_request,\n            {\n                0x05,   // Pairing Failed\n                0x05    // Pairing not Supported\n            }\n        );\n    }\n\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_FIXTURE_TEST_SUITE( lesc_and_legacy_pairing, test::security_manager<> )\n\n    BOOST_AUTO_TEST_CASE( accept_legacy_pairing_request )\n    {\n        expected(\n            lesc_pairing_request,\n            {\n                0x02,   // response\n                0x03,   // NoInputNoOutput\n                0x00,   // OOB Authentication data not present\n                0x08,   // Bonding, MITM = 0, SC = 1, Keypress = 0\n                0x10,   // Maximum Encryption Key Size\n                0x00,   // LinkKey\n                0x00    // LinkKey\n            }\n        );\n    }\n\n    BOOST_AUTO_TEST_CASE( accept_lesc_pairing_request )\n    {\n        expected(\n            legacy_pairing_request,\n            {\n                0x02,   // response\n                0x03,   // NoInputNoOutput\n                0x00,   // OOB Authentication data not present\n                0x08,   // Bonding, MITM = 0, SC = 1, Keypress = 0\n                0x10,   // Maximum Encryption Key Size\n                0x00,   // LinkKey\n                0x00    // LinkKey\n            }\n        );\n    }\n\nBOOST_AUTO_TEST_SUITE_END()\n\nstruct pass_key_display_t {\n    pass_key_display_t()\n        : displayed_pass_key( ~0 )\n        , called( false )\n    {\n    }\n\n    void sm_pairing_numeric_output( int pass_key )\n    {\n        BOOST_REQUIRE( !called );\n        called = true;\n\n        displayed_pass_key = pass_key;\n    }\n\n    int displayed_pass_key;\n    bool called;\n} pass_key_display;\n\nstruct yes_no_input_t\n{\n    void sm_pairing_yes_no( bluetoe::pairing_yes_no_response& response )\n    {\n        response.yes_no_response( true );\n    }\n} yes_no_input;\n\nusing lesc_security_manager_with_display_and_yes_no = test::lesc_security_manager< 65,\n    bluetoe::pairing_numeric_output< pass_key_display_t, pass_key_display >,\n    bluetoe::pairing_yes_no< yes_no_input_t, yes_no_input > >;\n\nBOOST_FIXTURE_TEST_CASE( lesc_numeric_comparison_pairing, lesc_security_manager_with_display_and_yes_no )\n{\n    expected(\n        {\n            0x01,       // Pairing request\n            0x01,       // DisplayYesNo\n            0x00,       // OOB Authentication data not present\n            0x08,       // No Bonding, No MITM, SC = 1\n            0x10,       // Maximum Encryption Key Size\n            0x00,       // Initiator Key Distribution\n            0x00        // Responder Key Distribution\n        },\n        {\n            0x02,       // Pairing Response\n            0x01,       // DisplayYesNo\n            0x00,       // OOB Authentication data not present\n            0x08,       // No Bonding, MITM = 0, SC = 1, Keypress = 0\n            0x10,       // Maximum Encryption Key Size\n            0x00,       // Initiator Key Distribution\n            0x00        // Responder Key Distribution\n        }\n    );\n}\n\n/**\n * SM/SLA/PROT/BV-02-C [SMP Time Out – IUT Responder]\n *\n * Verify that the IUT responder disconnects the link if pairing does not follow Pairing\n * Feature Exchange within 30 seconds after receiving Pairing Request command.\n */\n\n/**\n * SM/SLA/JW/BV-02-C [Just Works IUT Responder – Success]\n *\n * Verify that the IUT is able to perform the Just Works pairing procedure correctly when acting as peripheral, responder.\n */\nBOOST_FIXTURE_TEST_CASE( Just_Works_IUT_Responder__Success, test::legacy_security_manager<> )\n{\n    expected(\n        {\n            0x01,       // Pairing request\n            0x03,       // NoInputNoOutput\n            0x00,       // OOB Authentication data not present\n            0x00,       // No Bonding, No MITM\n            0x10,       // Maximum Encryption Key Size\n            0x00,       // Initiator Key Distribution\n            0x00        // Responder Key Distribution\n        },\n        {\n            0x02,       // Pairing Response\n            0x03,       // NoInputNoOutput\n            0x00,       // OOB Authentication data not present\n            0x00,       // No Bonding, MITM = 0, SC = 0, Keypress = 0\n            0x10,       // Maximum Encryption Key Size\n            0x00,       // Initiator Key Distribution\n            0x00        // Responder Key Distribution\n        }\n    );\n\n    expected_pairing_confirm_with_tk( {{ 0 }} );\n    BOOST_CHECK_EQUAL( connection_data().local_device_pairing_status(), bluetoe::device_pairing_status::unauthenticated_key );\n}\n\n/**\n * SM/SLA/JW/BI-03-C [Just Works IUT Responder – Handle AuthReq flag RFU correctly]\n *\n * Verify that the IUT is able to perform the Just Works pairing procedure when receiving additional\n * bits set in the AuthReq flag. Reserved For Future Use bits are correctly handled when acting as\n * peripheral, responder.\n */\nBOOST_FIXTURE_TEST_CASE( Just_Works_IUT_Responder__Handle_AuthReq_flag_RFU_correctly, test::legacy_security_manager<> )\n{\n    expected(\n        {\n            0x01,       // Pairing request\n            0x03,       // NoInputNoOutput\n            0x00,       // OOB Authentication data not present\n            0xE0,       // MITM set to ‘0’ and all reserved bits are set to ‘1’\n            0x10,       // Maximum Encryption Key Size\n            0x00,       // Initiator Key Distribution\n            0x00        // Responder Key Distribution\n        },\n        {\n            0x02,       // Pairing Response\n            0x03,       // NoInputNoOutput\n            0x00,       // OOB Authentication data not present\n            0x00,       // No Bonding, MITM = 0, SC = 0, Keypress = 0\n            0x10,       // Maximum Encryption Key Size\n            0x00,       // Initiator Key Distribution\n            0x00        // Responder Key Distribution\n        }\n    );\n\n    expected_pairing_confirm_with_tk( {{ 0 }} );\n    BOOST_CHECK_EQUAL( connection_data().local_device_pairing_status(), bluetoe::device_pairing_status::unauthenticated_key );\n}\n\n/**\n * SM/SLA/JW/BI-02-C [Just Works, IUT Responder – Failure]\n *\n * Verify that the IUT handles just works pairing failure as responder correctly.\n */\n\n/**\n * SM/SLA/PKE/BV-02-C (Passkey Entry, IUT Responder – Success)\n *\n * Verify that the IUT performs the Passkey Entry pairing procedure correctly as responder.\n */\n\nusing legacy_security_manager_with_display_only = test::legacy_security_manager< 23,\n    bluetoe::pairing_numeric_output< pass_key_display_t, pass_key_display > >;\n\nBOOST_FIXTURE_TEST_CASE( Passkey_Entry_IUT_Responder__Success, legacy_security_manager_with_display_only )\n{\n    expected(\n        {\n            0x01,       // Pairing request\n            0x04,       // KeyboardDisplay\n            0x00,       // OOB Authentication data not present\n            0x00,       // No Bonding, No MITM\n            0x10,       // Maximum Encryption Key Size\n            0x00,       // Initiator Key Distribution\n            0x00        // Responder Key Distribution\n        },\n        {\n            0x02,       // Pairing Response\n            0x00,       // DisplayOnly\n            0x00,       // OOB Authentication data not present\n            0x00,       // No Bonding, MITM = 0, SC = 0, Keypress = 0\n            0x10,       // Maximum Encryption Key Size\n            0x00,       // Initiator Key Distribution\n            0x00        // Responder Key Distribution\n        }\n    );\n\n    // passkey is ‘019655’\n    expected_pairing_confirm_with_tk( { { 0xC7, 0x4c } } );\n\n    BOOST_CHECK_EQUAL( pass_key_display.displayed_pass_key, 19655 );\n    BOOST_CHECK_EQUAL( connection_data().local_device_pairing_status(), bluetoe::device_pairing_status::authenticated_key );\n}\n\nstruct pairing_keyboard_handler_t\n{\n    pairing_keyboard_handler_t() : called( false )\n    {\n    }\n\n    int sm_pairing_passkey()\n    {\n        BOOST_REQUIRE( !called );\n        called = true;\n        return 19655;\n    }\n\n    bool called;\n} pairing_keyboard_handler;\n\nusing legacy_security_manager_with_keyboard = test::legacy_security_manager< 23,\n    bluetoe::pairing_keyboard< pairing_keyboard_handler_t, pairing_keyboard_handler > >;\n\nBOOST_FIXTURE_TEST_CASE( Passkey_Entry_IUT_Responder__Success_II, legacy_security_manager_with_keyboard )\n{\n    expected(\n        {\n            0x01,       // Pairing request\n            0x04,       // KeyboardDisplay\n            0x00,       // OOB Authentication data not present\n            0x00,       // No Bonding, No MITM\n            0x10,       // Maximum Encryption Key Size\n            0x00,       // Initiator Key Distribution\n            0x00        // Responder Key Distribution\n        },\n        {\n            0x02,       // Pairing Response\n            0x02,       // KeyboardOnly\n            0x00,       // OOB Authentication data not present\n            0x00,       // No Bonding, MITM = 0, SC = 0, Keypress = 0\n            0x10,       // Maximum Encryption Key Size\n            0x00,       // Initiator Key Distribution\n            0x00        // Responder Key Distribution\n        }\n    );\n\n    // passkey is ‘019655’\n    expected_pairing_confirm_with_tk( { { 0xC7, 0x4c } } );\n\n    BOOST_CHECK_EQUAL( connection_data().local_device_pairing_status(), bluetoe::device_pairing_status::authenticated_key );\n}\n\n/**\n * SM/SLA/PKE/BV-05-C [Passkey Entry, IUT Responder – Lower Tester has insufficient security for Passkey Entry]\n *\n * Verify that the IUT that supports the Passkey Entry pairing procedure as responder correctly\n * handles an initiator with insufficient security to result in an Authenticated key, yielding an\n * unauthenticated key.\n */\n\n/**\n * SM/SLA/PKE/BI-03-C [Passkey Entry, IUT Responder – Failure on Initiator Side]\n *\n * Verify that the IUT handles the invalid passkey entry pairing procedure correctly as responder.\n */\n\nstruct oob_cb_t {\n    static const std::array< std::uint8_t, 16 > oob_data;\n\n    std::pair< bool, std::array< std::uint8_t, 16 > > sm_oob_authentication_data(\n        const bluetoe::link_layer::device_address& address )\n    {\n        obb_requesting_remote_address = address;\n\n        return { true, oob_data };\n    }\n\n    bluetoe::link_layer::device_address obb_requesting_remote_address;\n} oob_cb;\n\nconst std::array< std::uint8_t, 16 > oob_cb_t::oob_data = {{\n        0xF1, 0x50, 0xA0, 0xAE,\n        0xB7, 0xAA, 0xBA, 0xC8,\n        0x19, 0x22, 0xB6, 0x15,\n        0x4C, 0x23, 0x94, 0x7A\n    }};\n\nusing legacy_security_manager_with_oob = test::legacy_security_manager< 23, bluetoe::oob_authentication_callback< oob_cb_t, oob_cb > >;\n\n/**\n * SM/SLA/OOB/BV-02-C [IUT Responder – Both sides have OOB data – Success]\n *\n * Verify that the IUT performs the OOB pairing procedure correctly as responder.\n */\nBOOST_FIXTURE_TEST_CASE( IUT_Responder_Both_sides_have_OOB_data_Success, legacy_security_manager_with_oob )\n{\n    expected(\n        {\n            0x01,       // Pairing request\n            0x03,       // NoInputNoOutput\n            0x01,       // OOB Authentication data from remote device present\n            0x00,       // No Bonding, No MITM\n            0x10,       // Maximum Encryption Key Size\n            0x00,       // Initiator Key Distribution\n            0x00        // Responder Key Distribution\n        },\n        {\n            0x02,       // Pairing Response\n            0x03,       // NoInputNoOutput\n            0x01,       // OOB Authentication data from remote device present\n            0x00,       // No Bonding, MITM = 0, SC = 0, Keypress = 0\n            0x10,       // Maximum Encryption Key Size\n            0x00,       // Initiator Key Distribution\n            0x00        // Responder Key Distribution\n        }\n    );\n\n    BOOST_CHECK_EQUAL( oob_cb.obb_requesting_remote_address,\n        bluetoe::link_layer::random_device_address({ 0xa6, 0xa5, 0xa4, 0xa3, 0xa2, 0xa1 }) );\n\n    expected_pairing_confirm_with_tk( oob_cb_t::oob_data );\n\n    BOOST_CHECK_EQUAL( connection_data().local_device_pairing_status(), bluetoe::device_pairing_status::authenticated_key );\n}\n\n/**\n * SM/SLA/OOB/BV-04-C [IUT Responder – Only IUT has OOB data – Success]\n *\n * Verify that the IUT performs the pairing procedure correctly as responder if only the\n * IUT has OOB data.\n */\n\n/**\n * SM/SLA/OOB/BV-06-C [IUT Responder – Only Lower Tester has OOB data – Success]\n *\n * Verify that the IUT performs the pairing procedure correctly as responder if only the Lower Tester has OOB data.\n */\n\n/**\n * SM/SLA/OOB/BV-08-C [IUT Responder – Only Lower Tester has OOB data – Lower Tester also supports Just Works]\n *\n * Verify that the IUT performs the pairing procedure correctly as responder if only the Lower Tester has OOB\n * data and supports the Just Works pairing method\n */\nBOOST_FIXTURE_TEST_CASE( IUT_Responder__Only_Lower_Tester_has_OOB_data__Lower_Tester_also_supports_Just_Works, test::legacy_security_manager<> )\n{\n    expected(\n        {\n            0x01,       // Pairing request\n            0x03,       // NoInputNoOutput\n            0x01,       // OOB Authentication data from remote device present\n            0x00,       // No Bonding, No MITM\n            0x10,       // Maximum Encryption Key Size\n            0x00,       // Initiator Key Distribution\n            0x00        // Responder Key Distribution\n        },\n        {\n            0x02,       // Pairing Response\n            0x03,       // NoInputNoOutput\n            0x00,       // no OOB Authentication data\n            0x00,       // No Bonding, MITM = 0, SC = 0, Keypress = 0\n            0x10,       // Maximum Encryption Key Size\n            0x00,       // Initiator Key Distribution\n            0x00        // Responder Key Distribution\n        }\n    );\n\n    expected_pairing_confirm_with_tk( {{ 0 }} );\n    BOOST_CHECK_EQUAL( connection_data().local_device_pairing_status(), bluetoe::device_pairing_status::unauthenticated_key );\n}\n\nstruct no_oob_cb_t {\n    std::pair< bool, std::array< std::uint8_t, 16 > > sm_oob_authentication_data(\n        const bluetoe::link_layer::device_address& )\n    {\n\n        return { false, {{0}} };\n    }\n} no_oob_cb;\n\nusing legacy_security_manager_with_no_oob = test::legacy_security_manager< 23,\n    bluetoe::oob_authentication_callback< no_oob_cb_t, no_oob_cb > >;\n\nBOOST_FIXTURE_TEST_CASE( IUT_Responder__Only_Lower_Tester_has_OOB_data__Lower_Tester_also_supports_Just_Works_II, test::legacy_security_manager<> )\n{\n    expected(\n        {\n            0x01,       // Pairing request\n            0x03,       // NoInputNoOutput\n            0x01,       // OOB Authentication data from remote device present\n            0x00,       // No Bonding, No MITM\n            0x10,       // Maximum Encryption Key Size\n            0x00,       // Initiator Key Distribution\n            0x00        // Responder Key Distribution\n        },\n        {\n            0x02,       // Pairing Response\n            0x03,       // NoInputNoOutput\n            0x00,       // no OOB Authentication data\n            0x00,       // No Bonding, MITM = 0, SC = 0, Keypress = 0\n            0x10,       // Maximum Encryption Key Size\n            0x00,       // Initiator Key Distribution\n            0x00        // Responder Key Distribution\n        }\n    );\n\n    expected_pairing_confirm_with_tk( {{ 0 }} );\n    BOOST_CHECK_EQUAL( connection_data().local_device_pairing_status(), bluetoe::device_pairing_status::unauthenticated_key );\n}\n\n/**\n * SM/SLA/OOB/BV-10-C [IUT Responder – Only IUT has OOB data – Lower Tester also supports Just Works]\n *\n * Verify that the IUT performs the pairing procedure correctly as responder if only the IUT has\n * OOB data and the Lower Tester supports the Just Works pairing method.\n */\nBOOST_FIXTURE_TEST_CASE( IUT_Responder__Only_IUT_has_OOB_data__Lower_Tester_also_supports_Just_Works, legacy_security_manager_with_oob )\n{\n    expected(\n        {\n            0x01,       // Pairing request\n            0x03,       // NoInputNoOutput\n            0x00,       // no OOB Authentication data\n            0x00,       // No Bonding, No MITM\n            0x10,       // Maximum Encryption Key Size\n            0x00,       // Initiator Key Distribution\n            0x00        // Responder Key Distribution\n        },\n        {\n            0x02,       // Pairing Response\n            0x03,       // NoInputNoOutput\n            0x01,       // OOB Authentication data from remote device present\n            0x00,       // No Bonding, MITM = 0, SC = 0, Keypress = 0\n            0x10,       // Maximum Encryption Key Size\n            0x00,       // Initiator Key Distribution\n            0x00        // Responder Key Distribution\n        }\n    );\n\n    expected_pairing_confirm_with_tk( {{ 0 }} );\n}\n\n/**\n * SM/SLA/OOB/BI-02-C [IUT Responder – Both sides have different OOB data – Failure]\n *\n * Verify that the IUT responds to OOB pairing procedure and handles the failure correctly.\n */\n"
  },
  {
    "path": "tests/security_manager/public_key_exchange_tests.cpp",
    "content": "#define BOOST_TEST_MODULE\n#include <boost/test/included/unit_test.hpp>\n\n#include <bluetoe/security_manager.hpp>\n\n#include \"test_sm.hpp\"\n\nBOOST_AUTO_TEST_SUITE( pairing_public_key_exchange )\n\n    BOOST_AUTO_TEST_CASE_TEMPLATE( request_too_small, Manager, test::lesc_managers )\n    {\n        test::lesc_pairing_features_exchanged< Manager > fixture;\n\n        fixture.expected(\n            {\n                0x0C,           // Pairing Public Key\n                // Public Key X\n                0xe6, 0x9d, 0x35, 0x0e,\n                0x48, 0x01, 0x03, 0xcc,\n                0xdb, 0xfd, 0xf4, 0xac,\n                0x11, 0x91, 0xf4, 0xef,\n                0xb9, 0xa5, 0xf9, 0xe9,\n                0xa7, 0x83, 0x2c, 0x5e,\n                0x2c, 0xbe, 0x97, 0xf2,\n                0xd2, 0x03, 0xb0, 0x20,\n                // Public Key Y\n                0x8b, 0xd2, 0x89, 0x15,\n                0xd0, 0x8e, 0x1c, 0x74,\n                0x24, 0x30, 0xed, 0x8f,\n                0xc2, 0x45, 0x63, 0x76,\n                0x5c, 0x15, 0x52, 0x5a,\n                0xbf, 0x9a, 0x32, 0x63,\n                0x6d, 0xeb, 0x2a, 0x65,\n                0x49, 0x9c, 0x80\n            },\n            {\n                0x05,           // Pairing Failed\n                0x0A,           // Invalid Parameters\n            }\n        );\n    }\n\n\n    BOOST_AUTO_TEST_CASE_TEMPLATE( request_too_large, Manager, test::lesc_managers )\n    {\n        test::lesc_pairing_features_exchanged< Manager > fixture;\n\n        fixture.expected(\n            {\n                0x0C,           // Pairing Public Key\n                // Public Key X\n                0xe6, 0x9d, 0x35, 0x0e,\n                0x48, 0x01, 0x03, 0xcc,\n                0xdb, 0xfd, 0xf4, 0xac,\n                0x11, 0x91, 0xf4, 0xef,\n                0xb9, 0xa5, 0xf9, 0xe9,\n                0xa7, 0x83, 0x2c, 0x5e,\n                0x2c, 0xbe, 0x97, 0xf2,\n                0xd2, 0x03, 0xb0, 0x20,\n                // Public Key Y\n                0x8b, 0xd2, 0x89, 0x15,\n                0xd0, 0x8e, 0x1c, 0x74,\n                0x24, 0x30, 0xed, 0x8f,\n                0xc2, 0x45, 0x63, 0x76,\n                0x5c, 0x15, 0x52, 0x5a,\n                0xbf, 0x9a, 0x32, 0x63,\n                0x6d, 0xeb, 0x2a, 0x65,\n                0x49, 0x9c, 0x80, 0xdc,\n                0x00                    // extra byte\n            },\n            {\n                0x05,           // Pairing Failed\n                0x0A,           // Invalid Parameters\n            }\n        );\n    }\n\n    BOOST_AUTO_TEST_CASE_TEMPLATE( key_not_on_valid_curve, Manager, test::lesc_managers )\n    {\n        test::lesc_pairing_features_exchanged< Manager > fixture;\n\n        fixture.expected(\n            {\n                0x0C,           // Pairing Public Key\n                // Public Key X\n                0xe6, 0x9d, 0x35, 0x0e,\n                0x48, 0x01, 0x03, 0xcc,\n                0xdb, 0xfd, 0xf4, 0xac,\n                0x11, 0x91, 0xf4, 0xef,\n                0xb9, 0xa5, 0xf9, 0xe9,\n                0xa7, 0x83, 0x2c, 0x5e,\n                0x2c, 0xbe, 0x97, 0xf2,\n                0xd2, 0x03, 0xb0, 0x20,\n                // Public Key Y\n                0x8b, 0xd2, 0x89, 0x15,\n                0xd0, 0x8e, 0x1c, 0x74,\n                0x24, 0x30, 0xed, 0x8f,\n                0xc2, 0x45, 0x63, 0x76,\n                0x5c, 0x15, 0x52, 0x5a,\n                0xbf, 0x9a, 0x32, 0x63,\n                0x6d, 0xeb, 0x2a, 0x65,\n                0x49, 0x9c, 0x80, 0x80  // <-- last nibble changed\n            },\n            {\n                0x05,           // Pairing Failed\n                0x0A,           // Invalid Parameters\n            }\n        );\n    }\n\n    BOOST_AUTO_TEST_CASE_TEMPLATE( valid_key, Manager, test::lesc_managers )\n    {\n        test::lesc_pairing_features_exchanged< Manager > fixture;\n\n        fixture.expected(\n            {\n                0x0C,                   // Pairing Public Key\n                // Public Key X\n                0xe6, 0x9d, 0x35, 0x0e,\n                0x48, 0x01, 0x03, 0xcc,\n                0xdb, 0xfd, 0xf4, 0xac,\n                0x11, 0x91, 0xf4, 0xef,\n                0xb9, 0xa5, 0xf9, 0xe9,\n                0xa7, 0x83, 0x2c, 0x5e,\n                0x2c, 0xbe, 0x97, 0xf2,\n                0xd2, 0x03, 0xb0, 0x20,\n                // Public Key Y\n                0x8b, 0xd2, 0x89, 0x15,\n                0xd0, 0x8e, 0x1c, 0x74,\n                0x24, 0x30, 0xed, 0x8f,\n                0xc2, 0x45, 0x63, 0x76,\n                0x5c, 0x15, 0x52, 0x5a,\n                0xbf, 0x9a, 0x32, 0x63,\n                0x6d, 0xeb, 0x2a, 0x65,\n                0x49, 0x9c, 0x80, 0xdc\n            },\n            {\n                0x0C,                   // Pairing Public Key\n                // Public Key X\n                0x90, 0xa1, 0xaa, 0x2f,\n                0xb2, 0x77, 0x90, 0x55,\n                0x9f, 0xa6, 0x15, 0x86,\n                0xfd, 0x8a, 0xb5, 0x47,\n                0x00, 0x4c, 0x9e, 0xf1,\n                0x84, 0x22, 0x59, 0x09,\n                0x96, 0x1d, 0xaf, 0x1f,\n                0xf0, 0xf0, 0xa1, 0x1e,\n                // Public Key Y\n                0x4a, 0x21, 0xb1, 0x15,\n                0xf9, 0xaf, 0x89, 0x5f,\n                0x76, 0x36, 0x8e, 0xe2,\n                0x30, 0x11, 0x2d, 0x47,\n                0x60, 0x51, 0xb8, 0x9a,\n                0x3a, 0x70, 0x56, 0x73,\n                0x37, 0xad, 0x9d, 0x42,\n                0x3e, 0xf3, 0x55, 0x4c,\n            }\n        );\n    }\n\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_CASE_TEMPLATE( not_expected_key_exchanged, Manager, test::lesc_managers )\n{\n    test::security_manager_base< Manager, test::all_security_functions, 65 > fixture;\n\n    fixture.expected(\n        {\n            0x0C,                   // Pairing Public Key\n            // Public Key X\n            0xe6, 0x9d, 0x35, 0x0e,\n            0x48, 0x01, 0x03, 0xcc,\n            0xdb, 0xfd, 0xf4, 0xac,\n            0x11, 0x91, 0xf4, 0xef,\n            0xb9, 0xa5, 0xf9, 0xe9,\n            0xa7, 0x83, 0x2c, 0x5e,\n            0x2c, 0xbe, 0x97, 0xf2,\n            0xd2, 0x03, 0xb0, 0x20,\n            // Public Key Y\n            0x8b, 0xd2, 0x89, 0x15,\n            0xd0, 0x8e, 0x1c, 0x74,\n            0x24, 0x30, 0xed, 0x8f,\n            0xc2, 0x45, 0x63, 0x76,\n            0x5c, 0x15, 0x52, 0x5a,\n            0xbf, 0x9a, 0x32, 0x63,\n            0x6d, 0xeb, 0x2a, 0x65,\n            0x49, 0x9c, 0x80, 0xdc\n        },\n        {\n            0x05,           // Pairing Failed\n            0x08,           // Unspecified Reason\n        }\n    );\n}\n"
  },
  {
    "path": "tests/security_manager/test_sm.hpp",
    "content": "#ifndef BLUETOE_TESTS_SECURITY_MANAGER_TEST_SM_HPP\n#define BLUETOE_TESTS_SECURITY_MANAGER_TEST_SM_HPP\n\n#include \"aes.h\"\n#include \"uECC.h\"\n#include <bluetoe/link_state.hpp>\n#include <bluetoe/security_manager.hpp>\n#include <bluetoe/address.hpp>\n\nnamespace test {\n    struct security_functions_base\n    {\n        bluetoe::link_layer::device_address local_address() const\n        {\n            return local_addr_;\n        }\n\n        void local_address( const bluetoe::link_layer::device_address& addr )\n        {\n            local_addr_ = addr;\n        }\n\n        bluetoe::details::uint128_t aes( bluetoe::details::uint128_t key, bluetoe::details::uint128_t data ) const\n        {\n            key  = r( key );\n            data = r( data );\n\n            AES_ctx ctx;\n            AES_init_ctx( &ctx, &key[ 0 ] );\n\n            AES_ECB_encrypt( &ctx, &data[ 0 ] );\n\n            return r( data );\n        }\n\n        bluetoe::details::uint128_t aes( bluetoe::details::uint128_t key, const std::uint8_t* data ) const\n        {\n            bluetoe::details::uint128_t input;\n            std::copy(data, data + 16u, input.begin());\n\n            return aes( key, input );\n        }\n\n    protected:\n        bluetoe::details::uint128_t r( const bluetoe::details::uint128_t& a ) const\n        {\n            const bluetoe::details::uint128_t result{{\n                a[15], a[14], a[13], a[12],\n                a[11], a[10], a[ 9], a[ 8],\n                a[ 7], a[ 6], a[ 5], a[ 4],\n                a[ 3], a[ 2], a[ 1], a[ 0],\n            }};\n\n            return result;\n        }\n\n        bluetoe::details::uint128_t xor_( bluetoe::details::uint128_t a, const bluetoe::details::uint128_t& b ) const\n        {\n            std::transform(\n                a.begin(), a.end(),\n                b.begin(),\n                a.begin(),\n                []( std::uint8_t a, std::uint8_t b ) -> std::uint8_t\n                {\n                    return a xor b;\n                }\n            );\n\n            return a;\n        }\n\n        bluetoe::details::uint128_t xor_( bluetoe::details::uint128_t a, const std::uint8_t* b ) const\n        {\n            std::transform(\n                a.begin(), a.end(),\n                b,\n                a.begin(),\n                []( std::uint8_t a, std::uint8_t b ) -> std::uint8_t\n                {\n                    return a xor b;\n                }\n            );\n\n            return a;\n        }\n    private:\n        bluetoe::link_layer::device_address local_addr_;\n    };\n\n    struct legacy_security_functions : virtual security_functions_base\n    {\n        bluetoe::details::uint128_t create_srand()\n        {\n            const bluetoe::details::uint128_t r{{\n                0xE0, 0x2E, 0x70, 0xC6,\n                0x4E, 0x27, 0x88, 0x63,\n                0x0E, 0x6F, 0xAD, 0x56,\n                0x21, 0xD5, 0x83, 0x57\n            }};\n\n            return r;\n        }\n\n        bluetoe::details::uint128_t create_passkey()\n        {\n            const bluetoe::details::uint128_t r{{\n                0xC7, 0x4c, 0x00, 0x00,\n                0x00, 0x00, 0x00, 0x00,\n                0x00, 0x00, 0x00, 0x00,\n                0x00, 0x00, 0x00, 0x00\n            }};\n\n            return r;\n        }\n\n        bluetoe::details::longterm_key_t create_long_term_key()\n        {\n            bluetoe::details::longterm_key_t key = {\n                {{\n                    0x00, 0x11, 0x22, 0x33,\n                    0x44, 0x55, 0x66, 0x77,\n                    0x88, 0x99, 0xaa, 0xbb,\n                    0xcc, 0xdd, 0xee, 0xff\n                }},\n                0xaabbccdd00112233,\n                0x1234\n            };\n\n            return key;\n        }\n\n        // Key generation function s1 for LE Legacy Pairing\n        bluetoe::details::uint128_t s1(\n            const bluetoe::details::uint128_t& stk,\n            const bluetoe::details::uint128_t& srand,\n            const bluetoe::details::uint128_t& mrand )\n        {\n            bluetoe::details::uint128_t r;\n            std::copy( &srand[ 0 ], &srand[ 8 ], &r[ 8 ] );\n            std::copy( &mrand[ 0 ], &mrand[ 8 ], &r[ 0 ] );\n\n            return aes( stk, r );\n        }\n\n        bluetoe::details::uint128_t c1(\n            const bluetoe::details::uint128_t& temp_key,\n            const bluetoe::details::uint128_t& srand,\n            const bluetoe::details::uint128_t& p1,\n            const bluetoe::details::uint128_t& p2 ) const\n        {\n            // c1 (k, r, preq, pres, iat, rat, ia, ra) = e(k, e(k, r XOR p1) XOR p2)\n            const auto p1_ = aes( temp_key, xor_( srand, p1 ) );\n\n            return aes( temp_key, xor_( p1_, p2 ) );\n        }\n\n    protected:\n        bluetoe::details::uint128_t r( const bluetoe::details::uint128_t& a ) const\n        {\n            const bluetoe::details::uint128_t result{{\n                a[15], a[14], a[13], a[12],\n                a[11], a[10], a[ 9], a[ 8],\n                a[ 7], a[ 6], a[ 5], a[ 4],\n                a[ 3], a[ 2], a[ 1], a[ 0],\n            }};\n\n            return result;\n        }\n\n    };\n\n    struct lesc_security_functions : virtual security_functions_base\n    {\n        bool is_valid_public_key( const std::uint8_t* public_key ) const\n        {\n            bluetoe::details::ecdh_public_key_t key;\n            std::reverse_copy(public_key, public_key + 32, key.begin());\n            std::reverse_copy(public_key + 32, public_key + 64, key.begin() + 32);\n\n            return uECC_valid_public_key( key.data() );\n        }\n\n        std::pair< bluetoe::details::ecdh_public_key_t, bluetoe::details::ecdh_private_key_t > generate_keys()\n        {\n            static const bluetoe::details::ecdh_public_key_t public_key = {\n                {\n                    // Public Key X\n                    0x90, 0xa1, 0xaa, 0x2f, 0xb2, 0x77, 0x90, 0x55,\n                    0x9f, 0xa6, 0x15, 0x86, 0xfd, 0x8a, 0xb5, 0x47,\n                    0x00, 0x4c, 0x9e, 0xf1, 0x84, 0x22, 0x59, 0x09,\n                    0x96, 0x1d, 0xaf, 0x1f, 0xf0, 0xf0, 0xa1, 0x1e,\n                    // Public Key Y\n                    0x4a, 0x21, 0xb1, 0x15, 0xf9, 0xaf, 0x89, 0x5f,\n                    0x76, 0x36, 0x8e, 0xe2, 0x30, 0x11, 0x2d, 0x47,\n                    0x60, 0x51, 0xb8, 0x9a, 0x3a, 0x70, 0x56, 0x73,\n                    0x37, 0xad, 0x9d, 0x42, 0x3e, 0xf3, 0x55, 0x4c\n                }\n            };\n\n            static const bluetoe::details::ecdh_private_key_t private_key = {\n                {\n                    0xfd, 0xc5, 0x7f, 0xf4, 0x49, 0xdd, 0x4f, 0x6b,\n                    0xfb, 0x7c, 0x9d, 0xf1, 0xc2, 0x9a, 0xcb, 0x59,\n                    0x2a, 0xe7, 0xd4, 0xee, 0xfb, 0xfc, 0x0a, 0x90,\n                    0x9a, 0xbb, 0xf6, 0x32, 0x3d, 0x8b, 0x18, 0x55\n                }\n            };\n\n            return { public_key, private_key };\n        }\n\n        bluetoe::details::uint128_t left_shift(const bluetoe::details::uint128_t& input)\n        {\n            bluetoe::details::uint128_t output;\n\n            std::uint8_t overflow = 0;\n            for ( std::size_t i = 0; i != input.size(); ++i )\n            {\n                output[ i ] = ( input[i] << 1 ) | overflow;\n                overflow = ( input[ i ] & 0x80 ) ? 1 : 0;\n            }\n\n            return output;\n        }\n\n        bluetoe::details::uint128_t aes_cmac_k1_subkey_generation( const bluetoe::details::uint128_t& key )\n        {\n            const bluetoe::details::uint128_t zero = {{ 0x00 }};\n            const bluetoe::details::uint128_t C    = {{ 0x87 }};\n\n            const bluetoe::details::uint128_t k0 = aes( key, zero );\n\n            const bluetoe::details::uint128_t k1 = ( k0.back() & 0x80 ) == 0\n                ? left_shift(k0)\n                : xor_( left_shift(k0), C );\n\n            return k1;\n        }\n\n        bluetoe::details::uint128_t aes_cmac_k2_subkey_generation( const bluetoe::details::uint128_t& key )\n        {\n            const bluetoe::details::uint128_t C    = {{ 0x87 }};\n\n            const bluetoe::details::uint128_t k1 = aes_cmac_k1_subkey_generation( key );\n            const bluetoe::details::uint128_t k2 = ( k1.back() & 0x80 ) == 0\n                ? left_shift(k1)\n                : xor_( left_shift(k1), C );\n\n            return k2;\n        }\n\n        bluetoe::details::uint128_t select_random_nonce()\n        {\n            static const bluetoe::details::uint128_t nonce = {{\n                0xab, 0xae, 0x2b, 0x71,\n                0xec, 0xb2, 0xff, 0xff,\n                0x3e, 0x73, 0x77, 0xd1,\n                0x54, 0x84, 0xcb, 0xd5\n            }};\n\n            return nonce;\n        }\n\n        bluetoe::details::ecdh_shared_secret_t p256( const std::uint8_t* private_key, const std::uint8_t* public_key )\n        {\n            bluetoe::details::ecdh_private_key_t shared_secret;\n            bluetoe::details::ecdh_private_key_t priv_key;\n            bluetoe::details::ecdh_public_key_t  pub_key;\n            std::reverse_copy( public_key, public_key + 32, pub_key.begin() );\n            std::reverse_copy( public_key + 32, public_key + 64, pub_key.begin() + 32 );\n            std::reverse_copy( private_key, private_key + 32, priv_key.begin() );\n\n            const int rc = uECC_shared_secret( pub_key.data(), priv_key.data(), shared_secret.data() );\n            static_cast< void >( rc );\n            assert( rc == 1 );\n\n            bluetoe::details::ecdh_shared_secret_t result;\n            std::reverse_copy( shared_secret.begin(), shared_secret.end(), result.begin() );\n\n            return result;\n        }\n\n        bluetoe::details::uint128_t f4( const std::uint8_t* u, const std::uint8_t* v, const std::array< std::uint8_t, 16 >& k, std::uint8_t z )\n        {\n            const bluetoe::details::uint128_t m4 = {{\n                0x00, 0x00, 0x00, 0x00,\n                0x00, 0x00, 0x00, 0x00,\n                0x00, 0x00, 0x00, 0x00,\n                0x00, 0x00, 0x80, z\n            }};\n\n            auto t0 = aes( k, &u[16] );\n            auto t1 = aes( k, xor_( t0, &u[0] ) );\n            auto t2 = aes( k, xor_( t1, &v[16] ) );\n            auto t3 = aes( k, xor_( t2, &v[0] ) );\n\n            return aes( k, xor_( t3, xor_( aes_cmac_k2_subkey_generation( k ), m4 ) ) );\n        }\n\n        std::pair< bluetoe::details::uint128_t, bluetoe::details::uint128_t > f5(\n            const bluetoe::details::ecdh_shared_secret_t dh_key,\n            const bluetoe::details::uint128_t& nonce_central,\n            const bluetoe::details::uint128_t& nonce_periperal,\n            const bluetoe::link_layer::device_address& addr_controller,\n            const bluetoe::link_layer::device_address& addr_peripheral )\n        {\n            // all 4 blocks are allocated in revers order to make it easier to copy data that overlaps\n            // two blocks\n            std::uint8_t buffer[ 64 ] = { 0 };\n\n            static const std::uint8_t m0_fill[] = {\n                0x65, 0x6c, 0x74, 0x62\n            };\n\n            static const std::uint8_t m3_fill[] = {\n                0x80, 0x00, 0x01\n            };\n\n            std::copy( std::begin( m0_fill ), std::end( m0_fill ), &buffer[ 11 + 48 ] );\n            std::copy( std::begin( m3_fill ), std::end( m3_fill ), &buffer[ 10 ] );\n\n            std::copy( nonce_central.begin(), nonce_central.end(), &buffer[ 32 + 11 ] );\n            std::copy( nonce_periperal.begin(), nonce_periperal.end(), &buffer[ 16 + 11 ] );\n\n            buffer[ 16 + 10 ] = addr_controller.is_random() ? 1 : 0;\n            std::copy( addr_controller.begin(), addr_controller.end(), &buffer[ 16 + 4 ] );\n            buffer[ 16 + 3 ] = addr_peripheral.is_random() ? 1 : 0;\n            std::copy( addr_peripheral.begin(), addr_peripheral.end(), &buffer[ 13 ] );\n\n            const bluetoe::details::uint128_t key     = f5_key( dh_key );\n            const bluetoe::details::uint128_t mac_key = f5_cmac( key, buffer );\n            // increment counter\n            buffer[ 15 + 48 ] = 1;\n            const bluetoe::details::uint128_t ltk     = f5_cmac( key, buffer );\n\n            return { mac_key, ltk };\n        }\n\n        bluetoe::details::uint128_t f6(\n            const bluetoe::details::uint128_t& key,\n            const bluetoe::details::uint128_t& n1,\n            const bluetoe::details::uint128_t& n2,\n            const bluetoe::details::uint128_t& r,\n            const bluetoe::details::io_capabilities_t& io_caps,\n            const bluetoe::link_layer::device_address& addr_controller,\n            const bluetoe::link_layer::device_address& addr_peripheral )\n        {\n            std::uint8_t m4_m3[ 32 ] = { 0 };\n\n            std::copy( io_caps.begin(), io_caps.end(), &m4_m3[ 16 + 13 ] );\n            m4_m3[ 16 + 12 ] = addr_controller.is_random() ? 1 : 0;\n            std::copy( addr_controller.begin(), addr_controller.end(), &m4_m3[ 22 ] );\n            m4_m3[ 16 + 5 ] = addr_peripheral.is_random() ? 1 : 0;\n            std::copy( addr_peripheral.begin(), addr_peripheral.end(), &m4_m3[ 15 ] );\n            m4_m3[ 14 ] = 0x80;\n\n            const std::uint8_t* m3 = &m4_m3[ 16 ];\n            const std::uint8_t* m4 = &m4_m3[ 0 ];\n\n            auto t0 = aes( key, n1 );\n            auto t1 = aes( key, xor_( t0, n2 ) );\n            auto t2 = aes( key, xor_( t1, r ) );\n            auto t3 = aes( key, xor_( t2, m3 ) );\n\n            return aes( key, xor_( t3, xor_( aes_cmac_k2_subkey_generation( key ), m4 ) ) );\n        }\n\n        std::uint32_t g2( const std::uint8_t* u, const std::uint8_t* v, const bluetoe::details::uint128_t& x, const bluetoe::details::uint128_t& y )\n        {\n            auto t0 = aes( x, u + 16 );\n            auto t1 = aes( x, xor_( t0, u ) );\n            auto t2 = aes( x, xor_( t1, v + 16 ) );\n            auto t3 = aes( x, xor_( t2, v ) );\n            auto t4 = aes( x, xor_( t3, xor_( aes_cmac_k1_subkey_generation( x ), y ) ) );\n\n            return bluetoe::details::read_32bit( t4.begin() );\n        }\n\n    private:\n        bluetoe::details::uint128_t f5_cmac(\n            const bluetoe::details::uint128_t& key,\n            const std::uint8_t* buffer )\n        {\n            const std::uint8_t* m0 = &buffer[ 48 ];\n            const std::uint8_t* m1 = &buffer[ 32 ];\n            const std::uint8_t* m2 = &buffer[ 16 ];\n            const std::uint8_t* m3 = &buffer[ 0 ];\n\n            auto t0 = aes( key, m0 );\n            auto t1 = aes( key, xor_( t0, m1 ) );\n            auto t2 = aes( key, xor_( t1, m2 ) );\n\n            return aes( key, xor_( t2, xor_( aes_cmac_k2_subkey_generation( key ), m3 ) ) );\n        }\n\n        bluetoe::details::uint128_t f5_key( const bluetoe::details::ecdh_shared_secret_t dh_key )\n        {\n            static const bluetoe::details::uint128_t salt = {{\n                0xBE, 0x83, 0x60, 0x5A, 0xDB, 0x0B, 0x37, 0x60,\n                0x38, 0xA5, 0xF5, 0xAA, 0x91, 0x83, 0x88, 0x6C\n            }};\n\n            auto t0 = aes( salt, &dh_key[ 16 ] );\n\n            return aes( salt, xor_( t0, xor_( aes_cmac_k1_subkey_generation( salt ), &dh_key[ 0 ] ) ) );\n        }\n    };\n\n    struct all_security_functions : legacy_security_functions, lesc_security_functions {};\n\n    template < class Manager, class SecurityFunctions, std::size_t MTU = 27, typename ...Options >\n    struct security_manager_base : Manager::template impl< security_manager_base< Manager, SecurityFunctions, MTU, Options... >, Options... >, SecurityFunctions\n    {\n        security_manager_base()\n            : connection_data_()\n        {\n            local_address(\n                bluetoe::link_layer::public_device_address({\n                    0xb6, 0xb5, 0xb4, 0xb3, 0xb2, 0xb1\n                })\n            );\n\n            remote_address(\n                bluetoe::link_layer::random_device_address({\n                    0xa6, 0xa5, 0xa4, 0xa3, 0xa2, 0xa1\n                })\n            );\n        }\n\n        void connect( const bluetoe::link_layer::device_address& addr )\n        {\n            connection_data_.remote_connection_created( addr );\n        }\n\n        void expected(\n            std::vector< std::uint8_t > input,\n            std::vector< std::uint8_t > expected_output )\n        {\n            std::uint8_t buffer[ MTU ];\n            std::size_t  size = MTU;\n\n            this->l2cap_output( buffer, size, connection_data_ );\n            BOOST_REQUIRE( size == 0 );\n            size = MTU;\n\n            this->l2cap_input( input.data(), input.size(), &buffer[ 0 ], size,\n                connection_data_ );\n\n            BOOST_CHECK_EQUAL_COLLECTIONS(\n                expected_output.begin(), expected_output.end(),\n                &buffer[ 0 ], &buffer[ size ] );\n        }\n\n        void expected(\n            std::initializer_list< std::uint8_t > in,\n            std::initializer_list< std::uint8_t > out )\n        {\n            std::vector< std::uint8_t > input( in.begin(), in.end() );\n            std::vector< std::uint8_t > output( out.begin(), out.end() );\n\n            expected( input, output );\n        }\n\n        void expected_ignoring_output_available(\n            std::initializer_list< std::uint8_t > input,\n            std::initializer_list< std::uint8_t > expected_output )\n        {\n            std::uint8_t buffer[ MTU ];\n            std::size_t  size = MTU;\n\n            this->l2cap_input( input.begin(), input.size(), &buffer[ 0 ], size, connection_data_ );\n\n            BOOST_CHECK_EQUAL_COLLECTIONS(\n                expected_output.begin(), expected_output.end(),\n                &buffer[ 0 ], &buffer[ size ] );\n        }\n\n        void expected(\n            std::initializer_list< std::uint8_t > expected_output )\n        {\n            std::uint8_t buffer[ MTU ];\n            std::size_t  size = MTU;\n\n            this->l2cap_output( &buffer[ 0 ], size, connection_data_ );\n\n            BOOST_CHECK_EQUAL_COLLECTIONS(\n                expected_output.begin(), expected_output.end(),\n                &buffer[ 0 ], &buffer[ size ] );\n        }\n\n        using manager_type      = typename Manager::template impl< SecurityFunctions, Options... >;\n        using connection_data_t =\n            typename manager_type::template channel_data_t< bluetoe::details::link_state >;\n\n        using SecurityFunctions::local_address;\n\n        void local_address( const bluetoe::link_layer::device_address& addr )\n        {\n            static_cast< SecurityFunctions& >( *this ).local_address( addr );\n        }\n\n        void remote_address( const bluetoe::link_layer::device_address& addr )\n        {\n            connection_data_.remote_connection_created( addr );\n        }\n\n        const connection_data_t& connection_data() const\n        {\n            return connection_data_;\n        }\n\n        void expected_pairing_confirm_with_tk( const std::array< std::uint8_t, 16 >& tk_value )\n        {\n            const bluetoe::details::uint128_t central_pairing_random = {{\n                0xE0, 0x2E, 0x70, 0xC6,\n                0x4E, 0x27, 0x88, 0x63,\n                0x0E, 0x6F, 0xAD, 0x56,\n                0x21, 0xD5, 0x83, 0x57\n            }};\n\n            std::vector< std::uint8_t > pairing_confirm_request( 17, 0x03 ); // Pairing Confirm\n            const auto central_pairing_confirm = this->c1( tk_value, central_pairing_random, connection_data_.c1_p1(), connection_data_.c1_p2() );\n            std::copy( central_pairing_confirm.begin(), central_pairing_confirm.end(), &pairing_confirm_request[ 1 ] );\n\n            std::vector< std::uint8_t > pairing_confirm_response( 17, 0x03 ); // Pairing Confirm\n            const auto sconfirm = this->c1( tk_value, connection_data_.srand(), connection_data_.c1_p1(), connection_data_.c1_p2() );\n            std::copy( sconfirm.begin(), sconfirm.end(), &pairing_confirm_response[ 1 ] );\n\n            // Paring Confirm\n            expected( pairing_confirm_request, pairing_confirm_response );\n\n            std::vector< std::uint8_t > pairing_random_request( 17, 0x04 ); // Pairing Random\n            std::copy( central_pairing_random.begin(), central_pairing_random.end(), &pairing_random_request[ 1 ] );\n\n            std::vector< std::uint8_t > pairing_random_response( 17, 0x04 ); // Pairing Random\n            const auto srand = connection_data_.srand();\n            std::copy( srand.begin(), srand.end(), &pairing_random_response[ 1 ] );\n\n            // Paring Random\n            expected( pairing_random_request, pairing_random_response );\n\n            const auto expected_stk = this->s1( tk_value, connection_data_.srand(), central_pairing_random );\n            const auto stored_stk   = connection_data_.find_key( 0, 0 );\n\n            BOOST_REQUIRE( stored_stk.first );\n            BOOST_CHECK_EQUAL_COLLECTIONS( expected_stk.begin(), expected_stk.end(), stored_stk.second.begin(), stored_stk.second.end() );\n        }\n\n        connection_data_t connection_data_;\n    };\n\n    template < std::size_t MTU = 23, typename ...Options >\n    using legacy_security_manager = security_manager_base< bluetoe::legacy_security_manager, test::legacy_security_functions, MTU, Options... >;\n\n    template < std::size_t MTU = 65, typename ...Options >\n    using lesc_security_manager = security_manager_base< bluetoe::lesc_security_manager, test::lesc_security_functions, MTU, Options... >;\n\n    template < std::size_t MTU = 65, typename ...Options >\n    using security_manager = security_manager_base< bluetoe::security_manager, test::all_security_functions, MTU, Options... >;\n\n    template < class Manager >\n    struct legacy_pairing_features_exchanged;\n\n    // The feature exchange is slightly different for the legacy-only manager compared to the LESC/legacy manager,\n    // because the combind manager indicates support for LESC in its response\n    template <>\n    struct legacy_pairing_features_exchanged< bluetoe::legacy_security_manager > : security_manager_base< bluetoe::legacy_security_manager, test::legacy_security_functions >\n    {\n        legacy_pairing_features_exchanged()\n        {\n            this->expected(\n                {\n                    0x01,           // Pairing Request\n                    0x01,           // IO Capability NoInputNoOutput\n                    0x00,           // OOB data flag (data not present)\n                    0x00,           // AuthReq\n                    0x10,           // Maximum Encryption Key Size (16)\n                    0x07,           // Initiator Key Distribution\n                    0x07,           // Responder Key Distribution (RFU)\n                },\n                {\n                    0x02,           // response\n                    0x03,           // NoInputNoOutput\n                    0x00,           // OOB Authentication data not present\n                    0x00,           // Bonding, MITM = 0, SC = 0, Keypress = 0\n                    0x10,           // Maximum Encryption Key Size\n                    0x00,           // LinkKey\n                    0x00            // LinkKey\n                }\n            );\n        }\n    };\n\n    template <>\n    struct legacy_pairing_features_exchanged< bluetoe::security_manager > : security_manager_base< bluetoe::security_manager, test::all_security_functions >\n    {\n        legacy_pairing_features_exchanged()\n        {\n            this->expected(\n                {\n                    0x01,           // Pairing Request\n                    0x01,           // IO Capability NoInputNoOutput\n                    0x00,           // OOB data flag (data not present)\n                    0x00,           // AuthReq\n                    0x10,           // Maximum Encryption Key Size (16)\n                    0x07,           // Initiator Key Distribution\n                    0x07,           // Responder Key Distribution (RFU)\n                },\n                {\n                    0x02,           // response\n                    0x03,           // NoInputNoOutput\n                    0x00,           // OOB Authentication data not present\n                    0x08,           // Bonding, MITM = 0, SC = 1, Keypress = 0\n                    0x10,           // Maximum Encryption Key Size\n                    0x00,           // LinkKey\n                    0x00            // LinkKey\n                }\n            );\n        }\n    };\n\n    template < class Manager >\n    struct lesc_pairing_features_exchanged : security_manager_base< Manager, test::all_security_functions, 65 >\n    {\n        lesc_pairing_features_exchanged()\n        {\n            this->expected(\n                {\n                    0x01,           // Pairing Request\n                    0x01,           // IO Capability NoInputNoOutput\n                    0x00,           // OOB data flag (data not present)\n                    0x08,           // AuthReq, SC = 1\n                    0x10,           // Maximum Encryption Key Size (16)\n                    0x07,           // Initiator Key Distribution\n                    0x07,           // Responder Key Distribution (RFU)\n                },\n                {\n                    0x02,           // response\n                    0x03,           // NoInputNoOutput\n                    0x00,           // OOB Authentication data not present\n                    0x08,           // Bonding, MITM = 0, SC = 1, Keypress = 0\n                    0x10,           // Maximum Encryption Key Size\n                    0x00,           // LinkKey\n                    0x00            // LinkKey\n                }\n            );\n        }\n    };\n\n    template < class Manager >\n    struct legacy_pairing_confirm_exchanged;\n\n    template <>\n    struct legacy_pairing_confirm_exchanged< bluetoe::legacy_security_manager > : legacy_pairing_features_exchanged< bluetoe::legacy_security_manager >\n    {\n        legacy_pairing_confirm_exchanged()\n        {\n            this->expected(\n                {\n                    0x03,                   // Pairing Confirm\n                    0xe2, 0x16, 0xb5, 0x44, // Confirm Value\n                    0x96, 0xa2, 0xe7, 0x90,\n                    0x53, 0xb2, 0x31, 0x06,\n                    0xc9, 0xdd, 0xd4, 0xf8\n                },\n                {\n                    0x03,                   // Pairing Confirm\n                    0xe2, 0x16, 0xb5, 0x44, // Confirm Value\n                    0x96, 0xa2, 0xe7, 0x90,\n                    0x53, 0xb2, 0x31, 0x06,\n                    0xc9, 0xdd, 0xd4, 0xf8\n                }\n            );\n        }\n    };\n\n    template <>\n    struct legacy_pairing_confirm_exchanged< bluetoe::security_manager > : legacy_pairing_features_exchanged< bluetoe::security_manager >\n    {\n        legacy_pairing_confirm_exchanged()\n        {\n            this->expected(\n                {\n                    0x03,                   // Pairing Confirm\n                    0xc9, 0x16, 0xcc, 0xf3, // Confirm Value\n                    0xf2, 0xb1, 0x6d, 0x8f,\n                    0xbb, 0x6d, 0x71, 0x4b,\n                    0x9c, 0xa7, 0xd8, 0xa8\n                },\n                {\n                    0x03,                   // Pairing Confirm\n                    0xc9, 0x16, 0xcc, 0xf3, // Confirm Value\n                    0xf2, 0xb1, 0x6d, 0x8f,\n                    0xbb, 0x6d, 0x71, 0x4b,\n                    0x9c, 0xa7, 0xd8, 0xa8\n                }\n            );\n        }\n    };\n\n    template < class Manager >\n    struct legacy_pairing_random_exchanged : legacy_pairing_confirm_exchanged< Manager >\n    {\n        legacy_pairing_random_exchanged()\n        {\n            this->expected(\n                {\n                    0x04,                   // opcode\n                    0xE0, 0x2E, 0x70, 0xC6,\n                    0x4E, 0x27, 0x88, 0x63,\n                    0x0E, 0x6F, 0xAD, 0x56,\n                    0x21, 0xD5, 0x83, 0x57\n                },\n                {\n                    0x04,                   // opcode\n                    0xE0, 0x2E, 0x70, 0xC6,\n                    0x4E, 0x27, 0x88, 0x63,\n                    0x0E, 0x6F, 0xAD, 0x56,\n                    0x21, 0xD5, 0x83, 0x57\n                }\n            );\n        }\n    };\n\n    template < class Manager >\n    struct lesc_public_key_exchanged : lesc_pairing_features_exchanged< Manager >\n    {\n        lesc_public_key_exchanged()\n        {\n            this->expected(\n                {\n                    0x0C,                   // Pairing Public Key\n                    // Public Key X\n                    0xe6, 0x9d, 0x35, 0x0e,\n                    0x48, 0x01, 0x03, 0xcc,\n                    0xdb, 0xfd, 0xf4, 0xac,\n                    0x11, 0x91, 0xf4, 0xef,\n                    0xb9, 0xa5, 0xf9, 0xe9,\n                    0xa7, 0x83, 0x2c, 0x5e,\n                    0x2c, 0xbe, 0x97, 0xf2,\n                    0xd2, 0x03, 0xb0, 0x20,\n                    // Public Key Y\n                    0x8b, 0xd2, 0x89, 0x15,\n                    0xd0, 0x8e, 0x1c, 0x74,\n                    0x24, 0x30, 0xed, 0x8f,\n                    0xc2, 0x45, 0x63, 0x76,\n                    0x5c, 0x15, 0x52, 0x5a,\n                    0xbf, 0x9a, 0x32, 0x63,\n                    0x6d, 0xeb, 0x2a, 0x65,\n                    0x49, 0x9c, 0x80, 0xdc\n                },\n                {\n                    0x0C,                   // Pairing Public Key\n                    // Public Key X\n                    0x90, 0xa1, 0xaa, 0x2f,\n                    0xb2, 0x77, 0x90, 0x55,\n                    0x9f, 0xa6, 0x15, 0x86,\n                    0xfd, 0x8a, 0xb5, 0x47,\n                    0x00, 0x4c, 0x9e, 0xf1,\n                    0x84, 0x22, 0x59, 0x09,\n                    0x96, 0x1d, 0xaf, 0x1f,\n                    0xf0, 0xf0, 0xa1, 0x1e,\n                    // Public Key Y\n                    0x4a, 0x21, 0xb1, 0x15,\n                    0xf9, 0xaf, 0x89, 0x5f,\n                    0x76, 0x36, 0x8e, 0xe2,\n                    0x30, 0x11, 0x2d, 0x47,\n                    0x60, 0x51, 0xb8, 0x9a,\n                    0x3a, 0x70, 0x56, 0x73,\n                    0x37, 0xad, 0x9d, 0x42,\n                    0x3e, 0xf3, 0x55, 0x4c,\n                }\n            );\n        }\n    };\n\n    template < class Manager >\n    struct lesc_pairing_confirmed : lesc_public_key_exchanged< Manager >\n    {\n        lesc_pairing_confirmed()\n        {\n            this->expected(\n                {\n                    0x03,           // Pairing Confirm\n                    0x99, 0x57, 0x89, 0x9b,\n                    0xaa, 0x41, 0x1b, 0x45,\n                    0x15, 0x8d, 0x58, 0xff,\n                    0x73, 0x9b, 0x81, 0xd1\n                }\n            );\n        }\n    };\n\n    template < class Manager >\n    struct lesc_pairing_random_exchanged : lesc_pairing_confirmed< Manager >\n    {\n        lesc_pairing_random_exchanged()\n        {\n            this->expected(\n                {\n                    0x04,           // Pairing Random\n                    0x00, 0x00, 0x00, 0x00,\n                    0x00, 0x00, 0x00, 0x00,\n                    0x00, 0x00, 0x00, 0x00,\n                    0x00, 0x00, 0x00, 0x00\n                },\n                {\n                    0x04,           // Pairing Random\n                    0xab, 0xae, 0x2b, 0x71,\n                    0xec, 0xb2, 0xff, 0xff,\n                    0x3e, 0x73, 0x77, 0xd1,\n                    0x54, 0x84, 0xcb, 0xd5\n                }\n            );\n        }\n    };\n\n    using lesc_managers = std::tuple<\n        bluetoe::lesc_security_manager,\n        bluetoe::security_manager >;\n\n    using legacy_managers = std::tuple<\n        bluetoe::legacy_security_manager,\n        bluetoe::security_manager >;\n\n} // namespace test\n\n#endif\n"
  },
  {
    "path": "tests/security_manager/test_sm_tests.cpp",
    "content": "#define BOOST_TEST_MODULE\n#include <boost/test/included/unit_test.hpp>\n\n#include <bluetoe/security_manager.hpp>\n#include \"test_sm.hpp\"\n\n/**\n * using the example data from Core (V5), Vol 3, Part H, 2.2.3 Confirm value generation function c1 for LE Legacy Pairing\n * p1 is 0x05000800000302070710000001010001\n * p2 is 0x00000000A1A2A3A4A5A6B1B2B3B4B5B6\n * 128-bit k is 0x00000000000000000000000000000000\n * 128-bit value r is 0x5783D52156AD6F0E6388274EC6702EE0\n * 128-bit output from the c1 function is 0x1e1e3fef878988ead2a74dc5bef13b86\n */\nBOOST_FIXTURE_TEST_CASE( c1_test, test::legacy_security_functions )\n{\n    const bluetoe::details::uint128_t p1{{\n        0x01, 0x00, 0x01, 0x01,\n        0x00, 0x00, 0x10, 0x07,\n        0x07, 0x02, 0x03, 0x00,\n        0x00, 0x08, 0x00, 0x05\n    }};\n\n    const bluetoe::details::uint128_t p2{{\n        0xB6, 0xB5, 0xB4, 0xB3,\n        0xB2, 0xB1, 0xA6, 0xA5,\n        0xA4, 0xA3, 0xA2, 0xA1,\n        0x00, 0x00, 0x00, 0x00\n    }};\n\n    const bluetoe::details::uint128_t k{{\n        0x00, 0x00, 0x00, 0x00,\n        0x00, 0x00, 0x00, 0x00,\n        0x00, 0x00, 0x00, 0x00,\n        0x00, 0x00, 0x00, 0x00\n    }};\n\n    const bluetoe::details::uint128_t r{{\n        0xE0, 0x2E, 0x70, 0xC6,\n        0x4E, 0x27, 0x88, 0x63,\n        0x0E, 0x6F, 0xAD, 0x56,\n        0x21, 0xD5, 0x83, 0x57\n    }};\n\n    const bluetoe::details::uint128_t expected{{\n        0x86, 0x3b, 0xf1, 0xbe,\n        0xc5, 0x4d, 0xa7, 0xd2,\n        0xea, 0x88, 0x89, 0x87,\n        0xef, 0x3f, 0x1e, 0x1e\n    }};\n\n    const bluetoe::details::uint128_t confirm = c1( k, r, p1, p2 );\n\n    BOOST_CHECK_EQUAL_COLLECTIONS(\n        confirm.begin(), confirm.end(), expected.begin(), expected.end() );\n}\n\n// For example if the 128-bit value r1 is 0x000F0E0D0C0B0A091122334455667788 then r1’ is 0x1122334455667788.\n// If the 128-bit value r2 is 0x010203040506070899AABBCCDDEEFF00 then r2’ is 0x99AABBCCDDEEFF00.\n// For example, if the 64-bit value r1’ is 0x1122334455667788 and r2’ is 0x99AABBCCDDEEFF00 then\n// r’ is 0x112233445566778899AABBCCDDEEFF00.\n// For example if the 128-bit value k is 0x00000000000000000000000000000000\n// and the 128-bit value r' is 0x112233445566778899AABBCCDDEEFF00\n// then the output from the key generation function s1 is 0x9a1fe1f0e8b0f49b5b4216ae796da062.\nBOOST_FIXTURE_TEST_CASE( s1_test, test::legacy_security_functions )\n{\n    static const bluetoe::details::uint128_t k = {\n        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00\n    };\n\n    // r1 = 0x000F0E0D0C0B0A091122334455667788\n    static const bluetoe::details::uint128_t r1 = {\n        0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11,\n        0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x00\n    };\n\n    // r2 = 0x010203040506070899AABBCCDDEEFF00\n    static const bluetoe::details::uint128_t r2 = {\n        0x00, 0xFF, 0xEE, 0xDD, 0xCC, 0xBB, 0xAA, 0x99,\n        0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01\n    };\n\n    // 0x9a1fe1f0e8b0f49b5b4216ae796da062\n    static const bluetoe::details::uint128_t expected = {\n        0x62, 0xa0, 0x6d, 0x79, 0xae, 0x16, 0x42, 0x5b,\n        0x9b, 0xf4, 0xb0, 0xe8, 0xf0, 0xe1, 0x1f, 0x9a\n    };\n\n    const bluetoe::details::uint128_t key = s1( k, r1, r2 );\n\n    BOOST_CHECK_EQUAL_COLLECTIONS(\n        key.begin(), key.end(), expected.begin(), expected.end() );\n}\n\nBOOST_FIXTURE_TEST_CASE( aes_test, test::legacy_security_functions )\n{\n    const bluetoe::details::uint128_t key{{\n        0x0f, 0x0e, 0x0d, 0x0c,\n        0x0b, 0x0a, 0x09, 0x08,\n        0x07, 0x06, 0x05, 0x04,\n        0x03, 0x02, 0x01, 0x00\n    }};\n\n    const bluetoe::details::uint128_t input{{\n        0xff, 0xee, 0xdd, 0xcc,\n        0xbb, 0xaa, 0x99, 0x88,\n        0x77, 0x66, 0x55, 0x44,\n        0x33, 0x22, 0x11, 0x00\n    }};\n\n    const bluetoe::details::uint128_t expected{{\n        0x5a, 0xc5, 0xb4, 0x70,\n        0x80, 0xb7, 0xcd, 0xd8,\n        0x30, 0x04, 0x7b, 0x6a,\n        0xd8, 0xe0, 0xc4, 0x69\n    }};\n\n    const bluetoe::details::uint128_t output = aes( key, input );\n\n    BOOST_CHECK_EQUAL_COLLECTIONS(\n        output.begin(), output.end(), expected.begin(), expected.end() );\n}\n\nBOOST_FIXTURE_TEST_CASE( xor_test, test::legacy_security_functions )\n{\n    const bluetoe::details::uint128_t p1{{\n        0x01, 0x00, 0x01, 0x01,\n        0x00, 0x00, 0x10, 0x07,\n        0x07, 0x02, 0x03, 0x00,\n        0x00, 0x08, 0x00, 0x05\n    }};\n\n    const bluetoe::details::uint128_t r{{\n        0xE0, 0x2E, 0x70, 0xC6,\n        0x4E, 0x27, 0x88, 0x63,\n        0x0E, 0x6F, 0xAD, 0x56,\n        0x21, 0xD5, 0x83, 0x57\n    }};\n\n    const bluetoe::details::uint128_t expected{{\n        0xe1, 0x2e, 0x71, 0xc7,\n        0x4e, 0x27, 0x98, 0x64,\n        0x09, 0x6d, 0xae, 0x56,\n        0x21, 0xdd, 0x83, 0x52\n    }};\n\n    const bluetoe::details::uint128_t output = xor_( p1, r );\n\n    BOOST_CHECK_EQUAL_COLLECTIONS(\n        output.begin(), output.end(), expected.begin(), expected.end() );\n}\n\nBOOST_FIXTURE_TEST_CASE( left_shift_tests, test::lesc_security_functions )\n{\n    const bluetoe::details::uint128_t input = {{\n        0x01, 0x00, 0x80, 0x00,\n        0x00, 0x00, 0x00, 0x00,\n        0xFF, 0x00, 0x00, 0x00,\n        0x04, 0x40, 0x00, 0xFF\n    }};\n\n    const bluetoe::details::uint128_t expected = {{\n        0x02, 0x00, 0x00, 0x01,\n        0x00, 0x00, 0x00, 0x00,\n        0xFE, 0x01, 0x00, 0x00,\n        0x08, 0x80, 0x00, 0xFE\n    }};\n\n    const bluetoe::details::uint128_t output = left_shift( input );\n\n    BOOST_CHECK_EQUAL_COLLECTIONS(\n        output.begin(), output.end(), expected.begin(), expected.end() );\n}\n\nBOOST_FIXTURE_TEST_CASE( k2_subkey_generation, test::lesc_security_functions )\n{\n    // --------------------------------------------------\n    // Subkey Generation\n    // K              2b7e1516 28aed2a6 abf71588 09cf4f3c\n    // AES-128(key,0) 7df76b0c 1ab899b3 3e42f047 b91b546f\n    // K1             fbeed618 35713366 7c85e08f 7236a8de\n    // K2             f7ddac30 6ae266cc f90bc11e e46d513b\n    // --------------------------------------------------\n\n    const bluetoe::details::uint128_t key = {{\n        0x3c, 0x4f, 0xcf, 0x09,\n        0x88, 0x15, 0xf7, 0xab,\n        0xa6, 0xd2, 0xae, 0x28,\n        0x16, 0x15, 0x7e, 0x2b\n    }};\n\n    const bluetoe::details::uint128_t expected = {{\n        0x3b, 0x51, 0x6d, 0xe4,\n        0x1e, 0xc1, 0x0b, 0xf9,\n        0xcc, 0x66, 0xe2, 0x6a,\n        0x30, 0xac, 0xdd, 0xf7\n    }};\n\n    const bluetoe::details::uint128_t output = aes_cmac_k2_subkey_generation( key );\n\n    BOOST_CHECK_EQUAL_COLLECTIONS(\n        output.begin(), output.end(), expected.begin(), expected.end() );\n}\n\nBOOST_FIXTURE_TEST_CASE( f4_test, test::lesc_security_functions )\n{\n    // 4 LE SC CONFIRM VALUE GENERATION FUNCTION\n    // U              20b003d2 f297be2c 5e2c83a7 e9f9a5b9\n    //                eff49111 acf4fddb cc030148 0e359de6\n    // V              55188b3d 32f6bb9a 900afcfb eed4e72a\n    //                59cb9ac2 f19d7cfb 6b4fdd49 f47fc5fd\n    // X              d5cb8454 d177733e ffffb2ec 712baeab\n    // Z 0x00\n    // M0             20b003d2 f297be2c 5e2c83a7 e9f9a5b9\n    // M1             eff49111 acf4fddb cc030148 0e359de6\n    // M2             55188b3d 32f6bb9a 900afcfb eed4e72a\n    // M3             59cb9ac2 f19d7cfb 6b4fdd49 f47fc5fd\n    // 00\n    // AES_CMAC       f2c916f1 07a9bd1c f1eda1be a974872d\n    const std::array< std::uint8_t, 32 > u = {{\n        0xe6, 0x9d, 0x35, 0x0e,\n        0x48, 0x01, 0x03, 0xcc,\n        0xdb, 0xfd, 0xf4, 0xac,\n        0x11, 0x91, 0xf4, 0xef,\n        0xb9, 0xa5, 0xf9, 0xe9,\n        0xa7, 0x83, 0x2c, 0x5e,\n        0x2c, 0xbe, 0x97, 0xf2,\n        0xd2, 0x03, 0xb0, 0x20\n    }};\n\n    const std::array< std::uint8_t, 32 > v = {{\n        0xfd, 0xc5, 0x7f, 0xf4,\n        0x49, 0xdd, 0x4f, 0x6b,\n        0xfb, 0x7c, 0x9d, 0xf1,\n        0xc2, 0x9a, 0xcb, 0x59,\n        0x2a, 0xe7, 0xd4, 0xee,\n        0xfb, 0xfc, 0x0a, 0x90,\n        0x9a, 0xbb, 0xf6, 0x32,\n        0x3d, 0x8b, 0x18, 0x55\n    }};\n\n    const bluetoe::details::uint128_t x = {{\n        0xab, 0xae, 0x2b, 0x71,\n        0xec, 0xb2, 0xff, 0xff,\n        0x3e, 0x73, 0x77, 0xd1,\n        0x54, 0x84, 0xcb, 0xd5\n    }};\n\n    const std::uint8_t z = 0x00;\n\n    const bluetoe::details::uint128_t expected{{\n        0x2d, 0x87, 0x74, 0xa9,\n        0xbe, 0xa1, 0xed, 0xf1,\n        0x1c, 0xbd, 0xa9, 0x07,\n        0xf1, 0x16, 0xc9, 0xf2\n    }};\n\n    const bluetoe::details::uint128_t output = f4( u.data(), v.data(), x, z );\n\n    BOOST_CHECK_EQUAL_COLLECTIONS(\n        output.begin(), output.end(), expected.begin(), expected.end() );\n}\n\n\nBOOST_FIXTURE_TEST_CASE( p256_tests, test::lesc_security_functions )\n{\n    const bluetoe::details::ecdh_private_key_t Private_A = {{\n        0xbd, 0x1a, 0x3c, 0xcd, 0xa6, 0xb8, 0x99, 0x58,\n        0x99, 0xb7, 0x40, 0xeb, 0x7b, 0x60, 0xff, 0x4a,\n        0x50, 0x3f, 0x10, 0xd2, 0xe3, 0xb3, 0xc9, 0x74,\n        0x38, 0x5f, 0xc5, 0xa3, 0xd4, 0xf6, 0x49, 0x3f\n    }};\n\n    const bluetoe::details::ecdh_private_key_t Private_B = {{\n        0xfd, 0xc5, 0x7f, 0xf4, 0x49, 0xdd, 0x4f, 0x6b,\n        0xfb, 0x7c, 0x9d, 0xf1, 0xc2, 0x9a, 0xcb, 0x59,\n        0x2a, 0xe7, 0xd4, 0xee, 0xfb, 0xfc, 0x0a, 0x90,\n        0x9a, 0xbb, 0xf6, 0x32, 0x3d, 0x8b, 0x18, 0x55\n    }};\n\n    const bluetoe::details::ecdh_public_key_t Public_A = {{\n        0xe6, 0x9d, 0x35, 0x0e, 0x48, 0x01, 0x03, 0xcc,\n        0xdb, 0xfd, 0xf4, 0xac, 0x11, 0x91, 0xf4, 0xef,\n        0xb9, 0xa5, 0xf9, 0xe9, 0xa7, 0x83, 0x2c, 0x5e,\n        0x2c, 0xbe, 0x97, 0xf2, 0xd2, 0x03, 0xb0, 0x20,\n\n        0x8b, 0xd2, 0x89, 0x15, 0xd0, 0x8e, 0x1c, 0x74,\n        0x24, 0x30, 0xed, 0x8f, 0xc2, 0x45, 0x63, 0x76,\n        0x5c, 0x15, 0x52, 0x5a, 0xbf, 0x9a, 0x32, 0x63,\n        0x6d, 0xeb, 0x2a, 0x65, 0x49, 0x9c, 0x80, 0xdc\n    }};\n\n    const bluetoe::details::ecdh_public_key_t Public_B = {{\n        0x90, 0xa1, 0xaa, 0x2f, 0xb2, 0x77, 0x90, 0x55,\n        0x9f, 0xa6, 0x15, 0x86, 0xfd, 0x8a, 0xb5, 0x47,\n        0x00, 0x4c, 0x9e, 0xf1, 0x84, 0x22, 0x59, 0x09,\n        0x96, 0x1d, 0xaf, 0x1f, 0xf0, 0xf0, 0xa1, 0x1e,\n\n        0x4a, 0x21, 0xb1, 0x15, 0xf9, 0xaf, 0x89, 0x5f,\n        0x76, 0x36, 0x8e, 0xe2, 0x30, 0x11, 0x2d, 0x47,\n        0x60, 0x51, 0xb8, 0x9a, 0x3a, 0x70, 0x56, 0x73,\n        0x37, 0xad, 0x9d, 0x42, 0x3e, 0xf3, 0x55, 0x4c\n    }};\n\n    const bluetoe::details::ecdh_shared_secret_t DHKey = {{\n        0x98, 0xa6, 0xbf, 0x73, 0xf3, 0x34, 0x8d, 0x86,\n        0xf1, 0x66, 0xf8, 0xb4, 0x13, 0x6b, 0x79, 0x99,\n        0x9b, 0x7d, 0x39, 0x0a, 0xa6, 0x10, 0x10, 0x34,\n        0x05, 0xad, 0xc8, 0x57, 0xa3, 0x34, 0x02, 0xec\n    }};\n\n    const auto shared_a = p256( Private_A.data(), Public_B.data() );\n\n    BOOST_CHECK_EQUAL_COLLECTIONS( DHKey.begin(), DHKey.end(), shared_a.begin(), shared_a.end() );\n\n    const auto shared_b = p256( Private_B.data(), Public_A.data() );\n\n    BOOST_CHECK_EQUAL_COLLECTIONS( DHKey.begin(), DHKey.end(), shared_b.begin(), shared_b.end() );\n}\n\nBOOST_FIXTURE_TEST_CASE( f5_test, test::lesc_security_functions )\n{\n    // DHKey(W) ec0234a3 57c8ad05 341010a6 0a397d9b\n    //          99796b13 b4f866f1 868d34f3 73bfa698\n    // T        3c128f20 de883288 97624bdb 8dac6989\n    // keyID    62746c65\n    // N1       d5cb8454 d177733e ffffb2ec 712baeab\n    // N2       a6e8e7cc 25a75f6e 216583f7 ff3dc4cf\n    // A1       00561237 37bfce\n    // A2       00a71370 2dcfc1\n    // Length   0100\n    // (LTK)\n    // M0       0162746c 65d5cb84 54d17773 3effffb2\n    // M1       ec712bae aba6e8e7 cc25a75f 6e216583\n    // M2       f7ff3dc4 cf005612 3737bfce 00a71370\n    // M3       2dcfc101 00\n    // AES_CMAC 69867911 69d7cd23 980522b5 94750a38\n    // (MacKey)\n    // M0       0062746c 65d5cb84 54d17773 3effffb2\n    // M1       ec712bae aba6e8e7 cc25a75f 6e216583\n    // M2       f7ff3dc4 cf005612 3737bfce 00a71370\n    // M3       2dcfc101 00\n    // AES_CMAC 965f176 a1084a02 fd3f6a20 ce636e20\n\n    const bluetoe::details::ecdh_shared_secret_t dh_key = {{\n        0x98, 0xa6, 0xbf, 0x73, 0xf3, 0x34, 0x8d, 0x86,\n        0xf1, 0x66, 0xf8, 0xb4, 0x13, 0x6b, 0x79, 0x99,\n        0x9b, 0x7d, 0x39, 0x0a, 0xa6, 0x10, 0x10, 0x34,\n        0x05, 0xad, 0xc8, 0x57, 0xa3, 0x34, 0x02, 0xec\n    }};\n\n    const bluetoe::details::uint128_t nonce_central = {{\n        0xab, 0xae, 0x2b, 0x71, 0xec, 0xb2, 0xff, 0xff,\n        0x3e, 0x73, 0x77, 0xd1, 0x54, 0x84, 0xcb, 0xd5\n    }};\n\n    const bluetoe::details::uint128_t nonce_periperal = {{\n        0xcf, 0xc4, 0x3d, 0xff, 0xf7, 0x83, 0x65, 0x21,\n        0x6e, 0x5f, 0xa7, 0x25, 0xcc, 0xe7, 0xe8, 0xa6\n    }};\n\n    const bluetoe::link_layer::public_device_address addr_controller({\n        0xce, 0xbf, 0x37, 0x37, 0x12, 0x56\n    });\n\n    const bluetoe::link_layer::public_device_address addr_peripheral({\n        0xc1, 0xcf, 0x2d, 0x70, 0x13, 0xa7\n    });\n\n    bluetoe::details::uint128_t mac_key;\n    bluetoe::details::uint128_t ltk;\n\n    std::tie( mac_key, ltk ) = f5( dh_key, nonce_central, nonce_periperal, addr_controller, addr_peripheral );\n\n    const bluetoe::details::uint128_t expected_mac_key = {{\n        0x20, 0x6e, 0x63, 0xce, 0x20, 0x6a, 0x3f, 0xfd,\n        0x02, 0x4a, 0x08, 0xa1, 0x76, 0xf1, 0x65, 0x29\n    }};\n\n    const bluetoe::details::uint128_t expected_ltk = {{\n        0x38, 0x0a, 0x75, 0x94, 0xb5, 0x22, 0x05, 0x98,\n        0x23, 0xcd, 0xd7, 0x69, 0x11, 0x79, 0x86, 0x69\n    }};\n\n    BOOST_CHECK_EQUAL_COLLECTIONS( mac_key.begin(), mac_key.end(), expected_mac_key.begin(), expected_mac_key.end() );\n    BOOST_CHECK_EQUAL_COLLECTIONS( ltk.begin(), ltk.end(), expected_ltk.begin(), expected_ltk.end() );\n}\n\nBOOST_FIXTURE_TEST_CASE( f6_test, test::lesc_security_functions )\n{\n    // D.4 f6 LE SC CHECK VALUE GENERATION FUNCTION\n    // N1             d5cb8454 d177733e ffffb2ec 712baeab\n    // N2             a6e8e7cc 25a75f6e 216583f7 ff3dc4cf\n    // MacKey         2965f176 a1084a02 fd3f6a20 ce636e20\n    // R              12a3343b b453bb54 08da42d2 0c2d0fc8\n    // IOcap          010102\n    // A1             00561237 37bfce\n    // A2             00a71370 2dcfc1\n    // M0             d5cb8454 d177733e ffffb2ec 712baeab\n    // M1             a6e8e7cc 25a75f6e 216583f7 ff3dc4cf\n    // M2             12a3343b b453bb54 08da42d2 0c2d0fc8\n    // M3             01010200 56123737 bfce00a7 13702dcf\n    // M4             c1\n    // AES_CMAC       e3c47398 9cd0e8c5 d26c0b09 da958f61\n\n    static const bluetoe::details::uint128_t nonce_central = {{\n        0xab, 0xae, 0x2b, 0x71, 0xec, 0xb2, 0xff, 0xff,\n        0x3e, 0x73, 0x77, 0xd1, 0x54, 0x84, 0xcb, 0xd5\n    }};\n\n    static const bluetoe::details::uint128_t nonce_periperal = {{\n        0xcf, 0xc4, 0x3d, 0xff, 0xf7, 0x83, 0x65, 0x21,\n        0x6e, 0x5f, 0xa7, 0x25, 0xcc, 0xe7, 0xe8, 0xa6\n    }};\n\n    static const bluetoe::details::uint128_t mac_key = {{\n        0x20, 0x6e, 0x63, 0xce, 0x20, 0x6a, 0x3f, 0xfd,\n        0x02, 0x4a, 0x08, 0xa1, 0x76, 0xf1, 0x65, 0x29\n    }};\n\n    static const bluetoe::details::uint128_t R = {{\n        0xc8, 0x0f, 0x2d, 0x0c, 0xd2, 0x42, 0xda, 0x08,\n        0x54, 0xbb, 0x53, 0xb4, 0x3b, 0x34, 0xa3, 0x12\n    }};\n\n    static const bluetoe::details::io_capabilities_t io_caps = {{\n        0x02, 0x01, 0x01\n    }};\n\n    static const bluetoe::link_layer::public_device_address addr_controller({\n        0xce, 0xbf, 0x37, 0x37, 0x12, 0x56\n    });\n\n    static const bluetoe::link_layer::public_device_address addr_peripheral({\n        0xc1, 0xcf, 0x2d, 0x70, 0x13, 0xa7\n    });\n\n    static const bluetoe::details::uint128_t expected_check_value = {{\n        0x61, 0x8f, 0x95, 0xda, 0x09, 0x0b, 0x6c, 0xd2,\n        0xc5, 0xe8, 0xd0, 0x9c, 0x98, 0x73, 0xc4, 0xe3\n    }};\n\n    static const bluetoe::details::uint128_t check_value = f6(\n        mac_key, nonce_central, nonce_periperal, R, io_caps, addr_controller, addr_peripheral );\n\n    BOOST_CHECK_EQUAL_COLLECTIONS( check_value.begin(), check_value.end(), expected_check_value.begin(), expected_check_value.end() );\n}\n\nBOOST_FIXTURE_TEST_CASE( g2_test, test::lesc_security_functions )\n{\n    // D.5 g2 LE SC NUMERIC COMPARISON GENERATION FUNCTION\n    // U              20b003d2 f297be2c 5e2c83a7 e9f9a5b9\n    //                eff49111 acf4fddb cc030148 0e359de6\n    // V              55188b3d 32f6bb9a 900afcfb eed4e72a\n    //                59cb9ac2 f19d7cfb 6b4fdd49 f47fc5fd\n    // X              d5cb8454 d177733e ffffb2ec 712baeab\n    // Y              a6e8e7cc 25a75f6e 216583f7 ff3dc4cf\n    // M0             20b003d2 f297be2c 5e2c83a7 e9f9a5b9\n    // M1             eff49111 acf4fddb cc030148 0e359de6\n    // M2             55188b3d 32f6bb9a 900afcfb eed4e72a\n    // M3             59cb9ac2 f19d7cfb 6b4fdd49 f47fc5fd\n    // M4             a6e8e7cc 25a75f6e 216583f7 ff3dc4cf\n    // AES_CMAC       1536d18d e3d20df9 9b7044c1 2f9ed5ba\n    // g2             2f9ed5ba\n\n    const std::array< std::uint8_t, 32 > u = {{\n        0xe6, 0x9d, 0x35, 0x0e,\n        0x48, 0x01, 0x03, 0xcc,\n        0xdb, 0xfd, 0xf4, 0xac,\n        0x11, 0x91, 0xf4, 0xef,\n        0xb9, 0xa5, 0xf9, 0xe9,\n        0xa7, 0x83, 0x2c, 0x5e,\n        0x2c, 0xbe, 0x97, 0xf2,\n        0xd2, 0x03, 0xb0, 0x20\n    }};\n\n    const std::array< std::uint8_t, 32 > v = {{\n        0xfd, 0xc5, 0x7f, 0xf4,\n        0x49, 0xdd, 0x4f, 0x6b,\n        0xfb, 0x7c, 0x9d, 0xf1,\n        0xc2, 0x9a, 0xcb, 0x59,\n        0x2a, 0xe7, 0xd4, 0xee,\n        0xfb, 0xfc, 0x0a, 0x90,\n        0x9a, 0xbb, 0xf6, 0x32,\n        0x3d, 0x8b, 0x18, 0x55\n    }};\n\n    const bluetoe::details::uint128_t x = {{\n        0xab, 0xae, 0x2b, 0x71,\n        0xec, 0xb2, 0xff, 0xff,\n        0x3e, 0x73, 0x77, 0xd1,\n        0x54, 0x84, 0xcb, 0xd5\n    }};\n\n    const bluetoe::details::uint128_t y = {{\n        0xcf, 0xc4, 0x3d, 0xff,\n        0xf7, 0x83, 0x65, 0x21,\n        0x6e, 0x5f, 0xa7, 0x25,\n        0xcc, 0xe7, 0xe8, 0xa6\n    }};\n\n    BOOST_CHECK_EQUAL( g2( u.data(), v.data(), x, y ), 0x2f9ed5bau );\n}\n"
  },
  {
    "path": "tests/server_tests.cpp",
    "content": "#define BOOST_TEST_MODULE\n#include <boost/test/included/unit_test.hpp>\n#include \"test_servers.hpp\"\n\n#include <bluetoe/server.hpp>\n\nBOOST_AUTO_TEST_SUITE( characteristic_configuration )\n\nstd::uint16_t temperature_value1 = 0x0104;\nstd::uint16_t temperature_value2 = 0x0104;\nstd::uint16_t temperature_value3 = 0x0104;\nstd::uint16_t temperature_value4 = 0x0104;\nstd::uint16_t temperature_value5 = 0x0104;\nstd::uint16_t temperature_value6 = 0x0104;\nstd::uint16_t temperature_value7 = 0x0104;\nstd::uint16_t temperature_value8 = 0x0104;\nstd::uint16_t temperature_value9 = 0x0104;\n\ntemplate < std::uint16_t* P, std::uint16_t ID >\nusing temp_char = bluetoe::characteristic<\n    bluetoe::characteristic_uuid16< ID >,\n    bluetoe::bind_characteristic_value< std::uint16_t, P >,\n    bluetoe::notify >;\n\ntypedef bluetoe::server<\n    bluetoe::service<\n        bluetoe::service_uuid< 0x8C8B4094, 0x0DE2, 0x499F, 0xA28A, 0x4EED5BC73CA9 >,\n        temp_char< &temperature_value1, 1 >,\n        temp_char< &temperature_value2, 2 >,\n        temp_char< &temperature_value3, 3 >,\n        temp_char< &temperature_value4, 4 >,\n        temp_char< &temperature_value5, 5 >,\n        temp_char< &temperature_value6, 6 >,\n        temp_char< &temperature_value7, 7 >,\n        temp_char< &temperature_value8, 8 >,\n        temp_char< &temperature_value9, 9 >\n    >\n> large_temperature_service;\n\ntemplate < class Server = large_temperature_service >\nstruct connection_data : Server::connection_data\n{\n    connection_data() : Server::connection_data() {}\n};\n\nBOOST_FIXTURE_TEST_CASE( characteristic_configuration_is_initialized_with_zereo, connection_data<> )\n{\n    BOOST_CHECK_EQUAL( 0, client_configurations().flags( 0 ) );\n    BOOST_CHECK_EQUAL( 0, client_configurations().flags( 1 ) );\n    // ...\n    BOOST_CHECK_EQUAL( 0, client_configurations().flags( 8 ) );\n}\n\nBOOST_FIXTURE_TEST_CASE( is_writeable, connection_data<> )\n{\n    client_configurations().flags( 0, 0x3 );\n    BOOST_CHECK_EQUAL( 0x3, client_configurations().flags( 0 ) );\n}\n\nBOOST_FIXTURE_TEST_CASE( configurations_are_independent, connection_data<> )\n{\n    client_configurations().flags( 0, 0x3 );\n    client_configurations().flags( 1, 0x2 );\n    client_configurations().flags( 2, 0x1 );\n    client_configurations().flags( 3, 0x1 );\n    client_configurations().flags( 4, 0x2 );\n    client_configurations().flags( 5, 0x3 );\n    BOOST_CHECK_EQUAL( 0x3, client_configurations().flags( 0 ) );\n    BOOST_CHECK_EQUAL( 0x2, client_configurations().flags( 1 ) );\n    BOOST_CHECK_EQUAL( 0x1, client_configurations().flags( 2 ) );\n    BOOST_CHECK_EQUAL( 0x1, client_configurations().flags( 3 ) );\n    BOOST_CHECK_EQUAL( 0x2, client_configurations().flags( 4 ) );\n    BOOST_CHECK_EQUAL( 0x3, client_configurations().flags( 5 ) );\n}\n\nBOOST_FIXTURE_TEST_CASE( is_clearable, connection_data<> )\n{\n    client_configurations().flags( 7, 0x3 );\n    client_configurations().flags( 7, 0x1 );\n    BOOST_CHECK_EQUAL( 0x1, client_configurations().flags( 7 ) );\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE( mixins )\n\nstd::string tag_construction_order;\n\nstruct reset_tag_construction_order\n{\n    reset_tag_construction_order()\n    {\n        tag_construction_order = \"\";\n    }\n};\n\ntemplate < char C >\nstruct tag\n{\n    tag()\n    {\n        tag_construction_order += C;\n    }\n};\n\n\nBOOST_FIXTURE_TEST_CASE( not_mixin, reset_tag_construction_order )\n{\n    test::three_apes_service three_appes;\n    BOOST_CHECK_EQUAL( tag_construction_order, \"\" );\n}\n\nBOOST_FIXTURE_TEST_CASE( empty_mixin, reset_tag_construction_order )\n{\n    bluetoe::server<\n        bluetoe::mixin<>\n    > server;\n\n    BOOST_CHECK_EQUAL( tag_construction_order, \"\" );\n}\n\nBOOST_FIXTURE_TEST_CASE( server_mixins, reset_tag_construction_order )\n{\n    bluetoe::server<\n        bluetoe::mixin< tag< 'A' > >\n    > server;\n\n    BOOST_CHECK_EQUAL( tag_construction_order, \"A\" );\n}\n\nBOOST_FIXTURE_TEST_CASE( multiple_server_mixins, reset_tag_construction_order )\n{\n    bluetoe::server<\n        bluetoe::mixin<>,\n        bluetoe::mixin< tag< 'A' > >,\n        bluetoe::mixin< tag< 'B' >, tag< 'C' > >\n    > server;\n\n    BOOST_CHECK_EQUAL( tag_construction_order, \"ABC\" );\n}\n\nBOOST_FIXTURE_TEST_CASE( single_service_mixin, reset_tag_construction_order )\n{\n    bluetoe::server<\n        bluetoe::service<\n            bluetoe::service_uuid16< 0x0815 >,\n            bluetoe::mixin< tag< 'A' > >\n        >\n    > server;\n\n    BOOST_CHECK_EQUAL( tag_construction_order, \"A\" );\n}\n\nBOOST_FIXTURE_TEST_CASE( multiple_service_mixin, reset_tag_construction_order )\n{\n    bluetoe::server<\n        bluetoe::service<\n            bluetoe::mixin< tag< 'A' > >,\n            bluetoe::service_uuid16< 0x0815 >,\n            bluetoe::mixin< tag< 'B' >, tag< 'C' > >\n        >\n    > server;\n\n    BOOST_CHECK_EQUAL( tag_construction_order, \"ABC\" );\n}\n\nBOOST_FIXTURE_TEST_CASE( multiple_service_and_server_mixin, reset_tag_construction_order )\n{\n    bluetoe::server<\n        bluetoe::mixin< tag< 'A' > >,\n        bluetoe::service<\n            bluetoe::mixin< tag< 'B' > >,\n            bluetoe::service_uuid16< 0x0815 >,\n            bluetoe::mixin< tag< 'C' >, tag< 'D' > >\n        >,\n        bluetoe::mixin< tag< 'E' > >,\n        bluetoe::service<\n            bluetoe::mixin< tag< 'F' > >,\n            bluetoe::service_uuid16< 0x0815 >,\n            bluetoe::mixin< tag< 'G' >, tag< 'H' > >\n        >,\n        bluetoe::mixin< tag< 'I' > >\n    > server;\n\n    BOOST_CHECK_EQUAL( tag_construction_order, \"AEIBCDFGH\" );\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n\n/*\n * Make sure, unauthorzed reads are reported as such and not just as read_not_permitted\n */\n\nBOOST_AUTO_TEST_SUITE( unauthorized_reads_and_writes )\n\n    char value = 0x42;\n\n    using server_t = bluetoe::server<\n        bluetoe::no_gap_service_for_gatt_servers,\n        bluetoe::service<\n            bluetoe::service_uuid16< 0x0815 >,\n            bluetoe::characteristic<\n                bluetoe::characteristic_uuid16< 0x0816 >,\n                bluetoe::bind_characteristic_value< char, &value >,\n                bluetoe::requires_encryption\n            >\n        >,\n        bluetoe::shared_write_queue< 255 >\n    >;\n\nBOOST_FIXTURE_TEST_CASE( read_request, test::request_with_reponse< server_t > )\n{\n    static const std::uint8_t read[] = { 0x0A, 0x03, 0x00 };\n\n    BOOST_CHECK( check_error_response( read, 0x0A, 0x0003, 0x05 ) );\n}\n\nBOOST_FIXTURE_TEST_CASE( read_blob_request, test::request_with_reponse< server_t > )\n{\n    static const std::uint8_t read[] = { 0x0C, 0x03, 0x00, 0x00, 0x00 };\n\n    BOOST_CHECK( check_error_response( read, 0x0C, 0x0003, 0x05 ) );\n}\n\nBOOST_FIXTURE_TEST_CASE( read_multiple_request, test::request_with_reponse< server_t > )\n{\n    static const std::uint8_t read[] = { 0x0E, 0x03, 0x00, 0x03, 0x00 };\n\n    BOOST_CHECK( check_error_response( read, 0x0E, 0x0003, 0x05 ) );\n}\n\nBOOST_FIXTURE_TEST_CASE( write_request, test::request_with_reponse< server_t > )\n{\n    static const std::uint8_t write[] = { 0x12, 0x03, 0x00, 0x00 };\n\n    BOOST_CHECK( check_error_response( write, 0x12, 0x0003, 0x05 ) );\n}\n\nBOOST_FIXTURE_TEST_CASE( prepair_write_request, test::request_with_reponse< server_t > )\n{\n    static const std::uint8_t write[] = { 0x16, 0x03, 0x00, 0x00, 0x00, 0x00 };\n\n    BOOST_CHECK( check_error_response( write, 0x16, 0x0003, 0x05 ) );\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n\n\nBOOST_AUTO_TEST_SUITE( cccd_updates )\n\n    struct callback_t {\n        template < class Server >\n        void client_characteristic_configuration_updated( Server&, const bluetoe::details::client_characteristic_configuration& data )\n        {\n            ++cb_called;\n            BOOST_CHECK_EQUAL( std::size_t{Server::number_of_client_configs}, 2u );\n\n            notified0  = data.flags(0);\n            indicated1 = data.flags(1);\n        }\n\n        int cb_called = 0;\n        std::uint16_t notified0 = 0;\n        std::uint16_t indicated1 = 0;\n    } callback;\n\n    struct reset_callback {\n        reset_callback()\n        {\n            callback = callback_t();\n        }\n    };\n\n    char value1 = 0x42;\n    char value2 = 0x42;\n\n    using server_t = bluetoe::server<\n        bluetoe::no_gap_service_for_gatt_servers,\n        bluetoe::service<\n            bluetoe::service_uuid16< 0x0815 >,\n            bluetoe::characteristic<\n                bluetoe::characteristic_uuid16< 0x0816 >,\n                bluetoe::bind_characteristic_value< char, &value1 >,\n                bluetoe::no_encryption_required,\n                bluetoe::notify\n            >,\n            bluetoe::characteristic<\n                bluetoe::characteristic_uuid16< 0x0817 >,\n                bluetoe::bind_characteristic_value< char, &value2 >,\n                bluetoe::no_encryption_required,\n                bluetoe::indicate\n            >\n        >,\n        bluetoe::client_characteristic_configuration_update_callback< callback_t, callback >,\n        bluetoe::mixin< reset_callback >\n    >;\n\nBOOST_FIXTURE_TEST_CASE( change_notification_subscription, test::request_with_reponse< server_t > )\n{\n    l2cap_input({ 0x12, 0x04, 0x00, 0x01, 0x00 });\n    expected_result( { 0x13 });\n\n    BOOST_CHECK_EQUAL( callback.cb_called, 1 );\n    BOOST_CHECK_EQUAL( callback.notified0, 0x01 );\n    BOOST_CHECK_EQUAL( callback.indicated1, 0x00 );\n}\n\nBOOST_FIXTURE_TEST_CASE( change_indication_subscription, test::request_with_reponse< server_t > )\n{\n    l2cap_input({ 0x12, 0x07, 0x00, 0x02, 0x00 });\n    expected_result( { 0x13 });\n\n    BOOST_CHECK_EQUAL( callback.cb_called, 1 );\n    BOOST_CHECK_EQUAL( callback.notified0, 0x00 );\n    BOOST_CHECK_EQUAL( callback.indicated1, 0x02 );\n}\n\nBOOST_FIXTURE_TEST_CASE( no_cb_call_on_none_changeing_write, test::request_with_reponse< server_t > )\n{\n    l2cap_input({ 0x12, 0x04, 0x00, 0x00, 0x00 });\n    expected_result( { 0x13 });\n\n    l2cap_input({ 0x12, 0x07, 0x00, 0x00, 0x00 });\n    expected_result( { 0x13 });\n\n    BOOST_CHECK_EQUAL( callback.cb_called, 0 );\n    BOOST_CHECK_EQUAL( callback.notified0, 0x00 );\n    BOOST_CHECK_EQUAL( callback.indicated1, 0x00 );\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "tests/service_tests.cpp",
    "content": "#include \"test_services.hpp\"\n#include \"hexdump.hpp\"\n#include <bluetoe/server.hpp>\n\n#define BOOST_TEST_MODULE\n#include <boost/test/included/unit_test.hpp>\n\n#include <iterator>\n\nusing srv = bluetoe::server<>;\n\nBOOST_AUTO_TEST_CASE( service_without_any_characteristic_results_in_one_attribute )\n{\n    const auto number = test::empty_service::number_of_attributes;\n    BOOST_CHECK_EQUAL( 1u, number );\n}\n\nBOOST_AUTO_TEST_CASE( first_attribute_is_the_primary_service )\n{\n    const auto attr = test::empty_service::attribute_at< std::tuple<>, 0, std::tuple< test::empty_service >, srv >( 0 );\n    BOOST_CHECK_EQUAL( 0x2800, attr.uuid );\n}\n\nstatic const std::uint8_t global_temperature_service_uuid[ 16 ] = { 0x2A, 0xD9, 0x91, 0x11, 0xAB, 0x5B, 0x58, 0xB0, 0x3B, 0x4F, 0x50, 0x44, 0x52, 0x6E, 0x42, 0xF0 };\n\nstatic void check_service_uuid( const bluetoe::details::attribute_access_arguments& args, std::size_t size = sizeof( global_temperature_service_uuid ) )\n{\n    BOOST_CHECK_EQUAL_COLLECTIONS( std::begin( global_temperature_service_uuid ), std::begin( global_temperature_service_uuid ) + size, args.buffer, args.buffer + args.buffer_size );\n}\n\nBOOST_AUTO_TEST_CASE( first_attribute_is_the_primary_service_and_can_be_read )\n{\n    const auto attr = test::empty_service::attribute_at< std::tuple<>, 0, std::tuple< test::empty_service >, srv >( 0 );\n    BOOST_REQUIRE( attr.access );\n\n    std::uint8_t buffer[ 16 ];\n    auto read = bluetoe::details::attribute_access_arguments::read( buffer, 0 );\n    const auto access_result = attr.access( read, 1 );\n\n    BOOST_CHECK( access_result == bluetoe::details::attribute_access_result::success );\n    check_service_uuid( read );\n}\n\nBOOST_AUTO_TEST_CASE( first_attribute_is_the_primary_service_and_can_be_read_buffer_larger )\n{\n    const auto attr = test::empty_service::attribute_at< std::tuple<>, 0, std::tuple< test::empty_service >, srv >( 0 );\n\n    std::uint8_t buffer[ 20 ];\n    auto read = bluetoe::details::attribute_access_arguments::read( buffer, 0 );\n    const auto access_result = attr.access( read, 1 );\n\n    BOOST_CHECK( access_result == bluetoe::details::attribute_access_result::success );\n    check_service_uuid( read );\n}\n\nBOOST_AUTO_TEST_CASE( first_attribute_is_the_primary_service_and_can_be_read_buffer_larger_with_offset )\n{\n    const auto attr = test::empty_service::attribute_at< std::tuple<>, 0, std::tuple< test::empty_service >, srv >( 0 );\n\n    std::uint8_t buffer[ 20 ];\n    auto read = bluetoe::details::attribute_access_arguments::read( buffer, 4 );\n    const auto access_result = attr.access( read, 1 );\n\n    BOOST_CHECK( access_result == bluetoe::details::attribute_access_result::success );\n    BOOST_CHECK_EQUAL_COLLECTIONS( std::begin( global_temperature_service_uuid ) + 4, std::end( global_temperature_service_uuid ),\n        &read.buffer[ 0 ], &read.buffer[ read.buffer_size ]);\n}\n\nBOOST_AUTO_TEST_CASE( first_attribute_is_the_primary_service_and_can_be_read_buffer_larger_with_offset_16 )\n{\n    const auto attr = test::empty_service::attribute_at< std::tuple<>, 0, std::tuple< test::empty_service >, srv >( 0 );\n\n    std::uint8_t buffer[ 20 ];\n    auto read = bluetoe::details::attribute_access_arguments::read( buffer, 16 );\n    const auto access_result = attr.access( read, 1 );\n\n    BOOST_CHECK( access_result == bluetoe::details::attribute_access_result::success );\n    BOOST_CHECK_EQUAL( 0u, read.buffer_size );\n}\n\nBOOST_AUTO_TEST_CASE( first_attribute_is_the_primary_service_and_can_be_read_buffer_to_small )\n{\n    const auto attr = test::empty_service::attribute_at< std::tuple<>, 0, std::tuple< test::empty_service >, srv >( 0 );\n\n    std::uint8_t buffer[ 15 ];\n    auto read = bluetoe::details::attribute_access_arguments::read( buffer, 0 );\n    const auto access_result = attr.access( read, 1 );\n\n    BOOST_CHECK( access_result == bluetoe::details::attribute_access_result::success );\n    check_service_uuid( read, sizeof( buffer ) );\n}\n\nBOOST_AUTO_TEST_CASE( write_to_primary_service )\n{\n    const auto attr = test::empty_service::attribute_at< std::tuple<>, 0, std::tuple< test::empty_service >, srv >( 0 );\n\n    std::uint8_t buffer[] = { 1, 2, 3 };\n    auto write = bluetoe::details::attribute_access_arguments::write( buffer );\n    const auto access_result = attr.access( write, 1 );\n\n    BOOST_CHECK( access_result == bluetoe::details::attribute_access_result::write_not_permitted );\n}\n\nBOOST_FIXTURE_TEST_CASE( accessing_all_attributes, test::service_with_3_characteristics )\n{\n    static constexpr std::size_t expected_number_of_attributes = 7u;\n    BOOST_REQUIRE_EQUAL( unsigned( number_of_attributes ), expected_number_of_attributes );\n\n    BOOST_CHECK_EQUAL( 0x2800, ( attribute_at< std::tuple<>, 0, std::tuple< test::service_with_3_characteristics >, srv >( 0 ).uuid ) );\n    BOOST_CHECK_EQUAL( 0x2803, ( attribute_at< std::tuple<>, 0, std::tuple< test::service_with_3_characteristics >, srv >( 1 ).uuid ) );\n    BOOST_CHECK_EQUAL( 0x0001, ( attribute_at< std::tuple<>, 0, std::tuple< test::service_with_3_characteristics >, srv >( 2 ).uuid ) );\n    BOOST_CHECK_EQUAL( 0x2803, ( attribute_at< std::tuple<>, 0, std::tuple< test::service_with_3_characteristics >, srv >( 3 ).uuid ) );\n    BOOST_CHECK_EQUAL( 0x0001, ( attribute_at< std::tuple<>, 0, std::tuple< test::service_with_3_characteristics >, srv >( 4 ).uuid ) );\n    BOOST_CHECK_EQUAL( 0x2803, ( attribute_at< std::tuple<>, 0, std::tuple< test::service_with_3_characteristics >, srv >( 5 ).uuid ) );\n    BOOST_CHECK_EQUAL( 0x0815, ( attribute_at< std::tuple<>, 0, std::tuple< test::service_with_3_characteristics >, srv >( 6 ).uuid ) );\n}\n\ntypedef std::tuple< test::service_with_3_characteristics > service_with_3_characteristics_list;\nusing server_with_3_characteristics_list = bluetoe::server< test::service_with_3_characteristics >;\n\nBOOST_FIXTURE_TEST_CASE( read_by_group_type_response, test::service_with_3_characteristics )\n{\n    std::uint8_t    buffer[ 100 ];\n    server_with_3_characteristics_list server;\n\n    std::uint8_t* const end = read_primary_service_response< std::tuple<>, 0, service_with_3_characteristics_list, bluetoe::server< test::service_with_3_characteristics> >( std::begin( buffer ), std::end( buffer ), 0u, true, server );\n\n    BOOST_CHECK_EQUAL( end - std::begin( buffer ), 20u );\n\n    static const std::uint8_t expected_result[] =\n    {\n        0x01, 0x00,              // Starting Handle\n        0x07, 0x00,              // Ending Handle\n        0xA9, 0x3C, 0xC7, 0x5B,  // Attribute Value == 128 bit UUID\n        0xED, 0x4E, 0x8A, 0xA2,\n        0x9F, 0x49, 0xE2, 0x0D,\n        0x94, 0x40, 0x8B, 0x8C\n    };\n\n    BOOST_CHECK_EQUAL_COLLECTIONS( std::begin( buffer ), end, std::begin( expected_result ), std::end( expected_result ) );\n}\n\nBOOST_FIXTURE_TEST_CASE( read_by_group_type_response_buffer_to_small, test::service_with_3_characteristics )\n{\n    std::uint8_t    buffer[ 19 ];\n    std::uint16_t   index = 1;\n    server_with_3_characteristics_list server;\n\n    std::uint8_t* const end = read_primary_service_response< std::tuple<>, 0, service_with_3_characteristics_list >( std::begin( buffer ), std::end( buffer ), index, true, server );\n\n    BOOST_CHECK( end == std::begin( buffer ) );\n}\n\ntypedef std::tuple< test::cycling_speed_and_cadence_service > cycling_speed_and_cadence_service_list;\n\nBOOST_FIXTURE_TEST_CASE( read_by_group_type_response_for_16bit_uuid, test::cycling_speed_and_cadence_service )\n{\n    std::uint8_t    buffer[ 100 ];\n    server_with_3_characteristics_list server;\n\n    std::uint8_t* const end = read_primary_service_response< std::tuple<>, 0, cycling_speed_and_cadence_service_list >( std::begin( buffer ), std::end( buffer ), 0u, false, server );\n\n    BOOST_CHECK_EQUAL( end - std::begin( buffer ), 6u );\n\n    static const std::uint8_t expected_result[] =\n    {\n        0x01, 0x00,   // Starting Handle\n        0x05, 0x00,   // Ending Handle\n        0x16, 0x18    // Attribute Value == 16 bit UUID\n    };\n\n    BOOST_CHECK_EQUAL_COLLECTIONS( std::begin( buffer ), end, std::begin( expected_result ), std::end( expected_result ) );\n}\n\nBOOST_FIXTURE_TEST_CASE( primary_service_value_compare_128bit, test::global_temperature_service )\n{\n    auto compare = bluetoe::details::attribute_access_arguments::compare_value( &global_temperature_service_uuid[ 0 ], &global_temperature_service_uuid[ sizeof global_temperature_service_uuid ], nullptr );\n    BOOST_CHECK( ( attribute_at< std::tuple<>, 0, std::tuple< test::global_temperature_service >, srv >( 0 ).access( compare, 1 ) == bluetoe::details::attribute_access_result::value_equal ) );\n}\n\nBOOST_AUTO_TEST_SUITE( number_of_client_configs )\n\nBOOST_AUTO_TEST_CASE( without_notifications_there_is_no_demand_for_client_configurations )\n{\n    BOOST_CHECK_EQUAL( 0, int( test::service_with_3_characteristics::number_of_client_configs ) );\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE( find_notification_data )\n\nchar v1, v2, v3;\n\ntypedef bluetoe::service<\n    bluetoe::service_uuid16< 0x8C8B >,\n    bluetoe::characteristic<\n        bluetoe::characteristic_uuid16< 0x8C8B >,\n        bluetoe::bind_characteristic_value< decltype( v1 ), &v1 >,\n        bluetoe::notify\n    >,\n    bluetoe::characteristic<\n        bluetoe::characteristic_uuid16< 0x8C8C >,\n        bluetoe::bind_characteristic_value< decltype( v2 ), &v2 >\n    >,\n    bluetoe::characteristic<\n        bluetoe::characteristic_uuid16< 0x8C8D >,\n        bluetoe::bind_characteristic_value< decltype( v3 ), &v3 >,\n        bluetoe::notify\n    >\n> service_with_2_notifications;\n\nBOOST_AUTO_TEST_CASE( service_with_2_notifications_has_2_client_configurations )\n{\n    BOOST_CHECK_EQUAL( 2, int( service_with_2_notifications::number_of_client_configs ) );\n}\n\n// just to be sure\nBOOST_FIXTURE_TEST_CASE( check_service_with_2_notifications_attribute_layout, service_with_2_notifications )\n{\n    BOOST_CHECK_EQUAL( 0x2800, ( attribute_at< std::tuple<>, 0, std::tuple< service_with_2_notifications >, srv >( 0 ).uuid ) );\n\n    BOOST_CHECK_EQUAL( 0x2803, ( attribute_at< std::tuple<>, 0, std::tuple< service_with_2_notifications >, srv >( 1 ).uuid ) );\n    BOOST_CHECK_EQUAL( 0x8C8B, ( attribute_at< std::tuple<>, 0, std::tuple< service_with_2_notifications >, srv >( 2 ).uuid ) );\n    BOOST_CHECK_EQUAL( 0x2902, ( attribute_at< std::tuple<>, 0, std::tuple< service_with_2_notifications >, srv >( 3 ).uuid ) );\n\n    BOOST_CHECK_EQUAL( 0x2803, ( attribute_at< std::tuple<>, 0, std::tuple< service_with_2_notifications >, srv >( 4 ).uuid ) );\n    BOOST_CHECK_EQUAL( 0x8C8C, ( attribute_at< std::tuple<>, 0, std::tuple< service_with_2_notifications >, srv >( 5 ).uuid ) );\n\n    BOOST_CHECK_EQUAL( 0x2803, ( attribute_at< std::tuple<>, 0, std::tuple< service_with_2_notifications >, srv >( 6 ).uuid ) );\n    BOOST_CHECK_EQUAL( 0x8C8D, ( attribute_at< std::tuple<>, 0, std::tuple< service_with_2_notifications >, srv >( 7 ).uuid ) );\n    BOOST_CHECK_EQUAL( 0x2902, ( attribute_at< std::tuple<>, 0, std::tuple< service_with_2_notifications >, srv >( 8 ).uuid ) );\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n\nstd::int32_t temperature;\n\nusing sensor_position_uuid = bluetoe::service_uuid< 0xD9473E00, 0xE7D3, 0x4D90, 0x9366, 0x282AC4F44FEB >;\nusing pizza_service_uuid   = bluetoe::service_uuid16< 0x3523 >;\n\ntypedef bluetoe::service<\n    bluetoe::service_uuid< 0x8C8B4094, 0x0DE2, 0x499F, 0xA28A, 0x4EED5BC73CA9 >,\n    bluetoe::include_service< sensor_position_uuid >,\n    bluetoe::characteristic<\n        bluetoe::bind_characteristic_value< decltype( temperature ), &temperature >,\n        bluetoe::no_read_access\n    >\n> temperature_service;\n\ntypedef bluetoe::secondary_service<\n    sensor_position_uuid,\n    bluetoe::characteristic<\n        bluetoe::fixed_uint8_value< 0x42 >\n    >\n> sensor_position_service;\n\ntypedef std::tuple< temperature_service, sensor_position_service > temperature_and_sensor_position_service;\ntypedef std::tuple< sensor_position_service, temperature_service > sensor_position_and_temperature_service;\n\nBOOST_AUTO_TEST_SUITE( secondary_service )\n\nBOOST_FIXTURE_TEST_CASE( find_secondary_service_definition, sensor_position_service )\n{\n    BOOST_CHECK_EQUAL( 0x2801, ( attribute_at< std::tuple<>, 0, temperature_and_sensor_position_service, srv >( 0 ).uuid ) );\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE( include_service )\n\nBOOST_FIXTURE_TEST_CASE( correct_number_of_attributes, temperature_service )\n{\n    BOOST_CHECK_EQUAL( int( number_of_attributes ), 4 );\n    BOOST_CHECK_EQUAL( int( number_of_characteristic_attributes ), 2 );\n    BOOST_CHECK_EQUAL( int( number_of_client_configs ), 0 );\n    BOOST_CHECK_EQUAL( int( number_of_service_attributes ), 2 );\n}\n\nBOOST_FIXTURE_TEST_CASE( find_include_definition_in_first_service, temperature_service )\n{\n    BOOST_CHECK_EQUAL( 0x2802, ( attribute_at< std::tuple<>, 0, sensor_position_and_temperature_service, srv >( 1 ).uuid ) );\n}\n\nBOOST_FIXTURE_TEST_CASE( find_include_definition_in_second_service, temperature_service )\n{\n    BOOST_CHECK_EQUAL( 0x2802, ( attribute_at< std::tuple<>, 0, temperature_and_sensor_position_service, srv >( 1 ).uuid ) );\n}\n\nBOOST_FIXTURE_TEST_CASE( read_include_definition_from_second_service_128_bit_uuid, temperature_service )\n{\n    std::uint8_t buffer[ 10 ];\n    auto read = bluetoe::details::attribute_access_arguments::read( buffer, 0 );\n    const auto access_result = attribute_at< std::tuple<>, 0, temperature_and_sensor_position_service, srv >( 1 ).access( read, 1 );\n\n    static const auto first_service_size = temperature_service::number_of_attributes;\n    static const auto second_service_size = sensor_position_service::number_of_attributes;\n\n    static const std::uint16_t service_attribute_handle = 1 + first_service_size;\n    static const std::uint16_t end_group_handle         = service_attribute_handle + second_service_size - 1;\n\n    static const std::uint8_t expected_result[] = {\n        service_attribute_handle & 0xff,\n        service_attribute_handle >> 8,\n        end_group_handle & 0xff,\n        end_group_handle >> 8\n    };\n\n    BOOST_CHECK_EQUAL_COLLECTIONS( std::begin( buffer ), std::begin( buffer ) + read.buffer_size,\n        std::begin( expected_result ), std::end( expected_result ) );\n    BOOST_CHECK( access_result == bluetoe::details::attribute_access_result::success );\n}\n\nBOOST_FIXTURE_TEST_CASE( read_include_definition_from_first_service_128_bit_uuid, temperature_service )\n{\n    std::uint8_t buffer[ 10 ];\n    auto read = bluetoe::details::attribute_access_arguments::read( buffer, 0 );\n    const auto access_result = attribute_at< std::tuple<>, 0, sensor_position_and_temperature_service, srv >( 1 ).access( read, 1 );\n\n    static const auto first_service_size = sensor_position_service::number_of_attributes;\n\n    static const std::uint16_t service_attribute_handle = 1;\n    static const std::uint16_t end_group_handle         = first_service_size;\n\n    static const std::uint8_t expected_result[] = {\n        service_attribute_handle & 0xff,\n        service_attribute_handle >> 8,\n        end_group_handle & 0xff,\n        end_group_handle >> 8\n    };\n\n    BOOST_CHECK_EQUAL_COLLECTIONS( std::begin( buffer ), std::begin( buffer ) + read.buffer_size,\n        std::begin( expected_result ), std::end( expected_result ) );\n    BOOST_CHECK( access_result == bluetoe::details::attribute_access_result::success );\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE( include_service_16_bit )\n\ntypedef bluetoe::service_uuid16< 0x1234 > pizza_service_uuid;\ntypedef bluetoe::service_uuid16< 0xabcd > beverages_service_uuid;\n\nusing pizza_service = bluetoe::service<\n    pizza_service_uuid,\n    bluetoe::include_service< beverages_service_uuid >,\n    bluetoe::characteristic<\n        bluetoe::characteristic_uuid16< 0x1234 >,\n        bluetoe::fixed_uint8_value< 0x42 >\n    >\n>;\n\nusing beverages_service = bluetoe::service<\n    beverages_service_uuid,\n    bluetoe::characteristic<\n        bluetoe::characteristic_uuid16< 0x1235 >,\n        bluetoe::fixed_uint8_value< 0x42 >\n    >\n>;\n\nusing pizza_and_drinks_service = std::tuple< pizza_service, beverages_service >;\n\nBOOST_FIXTURE_TEST_CASE( find_include_definition, pizza_service )\n{\n    BOOST_CHECK_EQUAL( 0x2802, ( attribute_at< std::tuple<>, 0, pizza_and_drinks_service, srv >( 1 ).uuid ) );\n}\n\nBOOST_FIXTURE_TEST_CASE( read_include_definition_from_service, pizza_service )\n{\n    std::uint8_t buffer[ 10 ];\n    auto read = bluetoe::details::attribute_access_arguments::read( buffer, 0 );\n    const auto access_result = attribute_at< std::tuple<>, 0, pizza_and_drinks_service, srv >( 1 ).access( read, 1 );\n\n    static const auto first_service_size  = pizza_service::number_of_attributes;\n    static const auto second_service_size = beverages_service::number_of_attributes;\n\n    static const std::uint16_t service_attribute_handle = 1 + first_service_size;\n    static const std::uint16_t end_group_handle         = service_attribute_handle + second_service_size - 1;\n\n    static const std::uint8_t expected_result[] = {\n        service_attribute_handle & 0xff,\n        service_attribute_handle >> 8,\n        end_group_handle & 0xff,\n        end_group_handle >> 8,\n        0xcd, 0xab\n    };\n\n    BOOST_CHECK_EQUAL_COLLECTIONS( std::begin( buffer ), std::begin( buffer ) + read.buffer_size,\n        std::begin( expected_result ), std::end( expected_result ) );\n    BOOST_CHECK( access_result == bluetoe::details::attribute_access_result::success );\n}\n\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "tests/services/CMakeLists.txt",
    "content": "add_library(test_gatt test_gatt.cpp)\ntarget_include_directories(test_gatt PUBLIC\n    ../test_tools\n    ${Boost_INCLUDE_DIR})\ntarget_link_libraries(test_gatt PUBLIC bluetoe::iface bluetoe::utility test::tools)\n\nadd_and_register_test(cscs_tests)\nadd_and_register_test(bootloader_tests)\nadd_and_register_test(battery_tests)\n\ntarget_link_libraries(bootloader_tests PRIVATE bluetoe::services test_gatt)\ntarget_link_libraries(cscs_tests PRIVATE bluetoe::services test_gatt)\ntarget_link_libraries(battery_tests PRIVATE bluetoe::services test_gatt)\n"
  },
  {
    "path": "tests/services/battery_tests.cpp",
    "content": "#include <bluetoe/services/bas.hpp>\n#include <bluetoe/server.hpp>\n\n#define BOOST_TEST_MODULE\n#include <boost/test/included/unit_test.hpp>\n\n#include \"test_gatt.hpp\"\n#include <iterator>\n\nint battery_level = 14;\n\nstruct battery_handler {\n    int read_battery_level()\n    {\n        return battery_level;\n    }\n};\n\nusing server_with_notification = bluetoe::server<\n    bluetoe::battery_level<\n        bluetoe::bas::handler< battery_handler >\n    >,\n    bluetoe::mixin< battery_handler >\n>;\n\nBOOST_FIXTURE_TEST_CASE( discover_service, test::gatt_procedures< server_with_notification > )\n{\n    const auto service = discover_primary_service_by_uuid< bluetoe::bas::service_uuid >();\n    BOOST_CHECK( service.starting_handle != service.ending_handle );\n}\n\nBOOST_FIXTURE_TEST_CASE( discover_characteristic, test::gatt_procedures< server_with_notification > )\n{\n    const auto service = discover_primary_service_by_uuid< bluetoe::bas::service_uuid >();\n    const auto chars   = discover_characteristic_by_uuid< bluetoe::bas::level_uuid >( service );\n\n    BOOST_CHECK( !( chars == test::discovered_characteristic() ) );\n}\n\nstruct discovered : test::gatt_procedures< server_with_notification >\n{\n    discovered()\n    {\n        battery_level   = 14;\n        service         = discover_primary_service_by_uuid< bluetoe::bas::service_uuid >();\n        characteristic  = discover_characteristic_by_uuid< bluetoe::bas::level_uuid >( service );\n        cccd            = discover_cccd( characteristic );\n    }\n\n    test::discovered_service                    service;\n    test::discovered_characteristic             characteristic;\n    test::discovered_characteristic_descriptor  cccd;\n};\n\nBOOST_FIXTURE_TEST_CASE( check_level_value, discovered )\n{\n    l2cap_input({\n        0x0A,                       // read request\n        low( characteristic.value_handle ),\n        high( characteristic.value_handle )\n    });\n\n    expected_result( {\n        0x0B,                       // read response\n        14\n    });\n\n    battery_level = 42;\n\n    l2cap_input({\n        0x0A,                       // read request\n        low( characteristic.value_handle ),\n        high( characteristic.value_handle )\n    });\n\n    expected_result( {\n        0x0B,                       // read response\n        42\n    });\n}\n\nBOOST_FIXTURE_TEST_CASE( check_characteristic_properties, discovered )\n{\n    BOOST_CHECK_EQUAL(\n        characteristic.properties,\n        0x02                            // Read\n      | 0x10                            // Notify\n    );\n}\n\nBOOST_FIXTURE_TEST_CASE( check_cccd, discovered )\n{\n    BOOST_REQUIRE_NE( cccd.handle, test::invalid_handle );\n}\n\nstruct discovered_and_subscribed : discovered\n{\n    discovered_and_subscribed()\n    {\n        l2cap_input({\n            0x12,               //  Write Request\n            low( cccd.handle ),\n            high( cccd.handle ),\n            0x01, 0x00          // notifications\n        });\n\n        expected_result( { 0x13 } );\n    }\n};\n\nBOOST_FIXTURE_TEST_CASE( notifying_level, discovered_and_subscribed )\n{\n    battery_level = 33;\n\n    notifiy_battery_level( *this );\n\n    expected_output( notification, {\n        0x1B,                       // Notification\n        low( characteristic.value_handle ),\n        high( characteristic.value_handle ),\n        33\n    });\n}\n\nusing server_with_encryption = bluetoe::server<\n    bluetoe::battery_level<\n        bluetoe::bas::handler< battery_handler >,\n        bluetoe::requires_encryption\n    >,\n    bluetoe::mixin< battery_handler >\n>;\n\nBOOST_FIXTURE_TEST_CASE( make_sure_other_service_args_are_forwarded, test::gatt_procedures< server_with_encryption > )\n{\n    const auto service = discover_primary_service_by_uuid< bluetoe::bas::service_uuid >();\n    BOOST_CHECK( service.starting_handle != service.ending_handle );\n\n    test::discovered_characteristic value_char = discover_characteristic_by_uuid< bluetoe::bas::level_uuid >( service );\n\n    l2cap_input({\n        0x0A,                       // read request\n        low( value_char.value_handle ),\n        high( value_char.value_handle )\n    });\n\n    expected_result( {\n        0x01,                       // error response\n        0x0A,                       // read request\n        low( value_char.value_handle ),\n        high( value_char.value_handle ),\n        0x05                        // Insufficient Authentication\n    });\n}\n"
  },
  {
    "path": "tests/services/bootloader_tests.cpp",
    "content": "#include <iostream>\n#include <iomanip>\n#include <random>\n#include <hexdump.hpp>\n#include <test_uuid.hpp>\n\n#include <bluetoe/server.hpp>\n#include <bootloader.hpp>\n\n#define BOOST_TEST_MODULE\n#include <boost/test/included/unit_test.hpp>\n\n#include \"test_gatt.cpp\"\n\nusing namespace test;\n\nstatic constexpr std::size_t flash_start_addr  = 0x1000;\nstatic constexpr std::size_t flash_start_addr2 = 0x2000;\nstatic constexpr std::size_t block_size = 0x100;\nstatic constexpr std::size_t num_blocks = 4;\nstatic constexpr std::size_t test_mtu_size = 23;\n\nstruct handler {\n    std::pair< const std::uint8_t*, std::size_t > get_version()\n    {\n        static const std::uint8_t version[] = { 0x47, 0x11 };\n        return std::pair< const std::uint8_t*, std::size_t >( version, sizeof( version ) );\n    }\n\n    void read_mem( std::uintptr_t address, std::size_t size, std::uint8_t* destination )\n    {\n        assert( address >= flash_start_addr );\n        assert( address + size <= flash_start_addr + block_size * num_blocks );\n\n        std::copy( &device_memory[ address - flash_start_addr ], &device_memory[ address - flash_start_addr + size ], destination );\n    }\n\n    std::uint32_t checksum32( std::uintptr_t start_addr, std::size_t size )\n    {\n        std::uint32_t result = 0;\n\n        for ( std::uintptr_t i = start_addr; i != start_addr + size; ++i )\n        {\n            result += device_memory.at( i - flash_start_addr );\n        }\n\n        return result;\n    }\n\n    std::uint32_t checksum32( const std::uint8_t* start_addr, std::size_t size, std::uint32_t result )\n    {\n        for ( ; size; ++start_addr, --size )\n        {\n            result += *start_addr;\n        }\n\n        return result;\n    }\n\n    std::uint32_t checksum32( std::uintptr_t start_addr )\n    {\n        std::uint32_t result = 0;\n\n        while ( start_addr )\n        {\n            result += start_addr & 0xff;\n            start_addr = start_addr >> 8;\n        }\n\n        return result;\n    }\n\n    bluetoe::bootloader::error_codes public_read_mem( std::uintptr_t address, std::size_t size, std::uint8_t* destination )\n    {\n        if ( report_read_error_cnt_ == 0 )\n            return bluetoe::bootloader::error_codes::not_authorized;\n\n        if ( report_read_error_cnt_ > 0 )\n            --report_read_error_cnt_;\n\n        read_mem( address, size, destination );\n\n        return bluetoe::bootloader::error_codes::success;\n    }\n\n    void report_read_error( int counter )\n    {\n        report_read_error_cnt_ = counter;\n    }\n\n    std::uint32_t public_checksum32( std::uintptr_t start_addr, std::size_t size )\n    {\n        return fixed_crc_ == 0\n            ? checksum32( start_addr, size )\n            : fixed_crc_;\n    }\n\n    bluetoe::bootloader::error_codes start_flash( std::uintptr_t address, const std::uint8_t* values, std::size_t size )\n    {\n        start_flash_address = address;\n        start_flash_content.insert( start_flash_content.end(), values, values + size );\n\n        std::copy( values, values + size, &device_memory[ address - flash_start_addr ] );\n\n        return bluetoe::bootloader::error_codes::success;\n    }\n\n    bluetoe::bootloader::error_codes run( std::uintptr_t start_addr )\n    {\n        start_program_called = start_addr;\n\n        return bluetoe::bootloader::error_codes::success;\n    }\n\n    bluetoe::bootloader::error_codes reset()\n    {\n        reset_called = true;\n\n        return bluetoe::bootloader::error_codes::success;\n    }\n\n    void control_point_notification_call_back()\n    {\n        control_point_notification_requested_ = true;\n    }\n\n    bool control_point_notification_requested()\n    {\n        const bool result = control_point_notification_requested_;\n        control_point_notification_requested_ = false;\n\n        return result;\n    }\n\n    void data_indication_call_back()\n    {\n        data_indication_requested_ = true;\n    }\n\n    bool data_indication_requested()\n    {\n        const bool result = data_indication_requested_;\n        data_indication_requested_ = false;\n\n        return result;\n    }\n    void report_fixed_public_crc( std::uint32_t crc )\n    {\n        fixed_crc_ = crc;\n    }\n\n    handler()\n        : start_flash_address( 0x1234 )\n        , start_program_called( 0 )\n        , reset_called( false )\n        , control_point_notification_requested_( false )\n        , data_indication_requested_( false )\n        , report_read_error_cnt_( -1 )\n        , fixed_crc_( 0 )\n    {\n        for ( int b = 0; b != num_blocks; ++b )\n        {\n            for ( int v = 0; v != block_size; ++v )\n                device_memory.push_back( v );\n        }\n\n        original_device_memory = device_memory;\n    }\n\n    std::vector< std::uint8_t > device_memory;\n    std::vector< std::uint8_t > original_device_memory;\n    std::uintptr_t              start_flash_address;\n    std::vector< std::uint8_t > start_flash_content;\n    std::uintptr_t              start_program_called;\n    bool                        reset_called;\n    bool                        control_point_notification_requested_;\n    bool                        data_indication_requested_;\n    int                         report_read_error_cnt_;\n    std::uint32_t               fixed_crc_;\n};\n\nusing bootloader_server = bluetoe::server<\n    bluetoe::bootloader_service<\n        bluetoe::bootloader::page_size< block_size >,\n        bluetoe::bootloader::handler< handler >,\n        bluetoe::bootloader::white_list<\n            bluetoe::bootloader::memory_region< flash_start_addr, flash_start_addr + num_blocks * block_size >,\n            bluetoe::bootloader::memory_region< flash_start_addr2, flash_start_addr2 + num_blocks * block_size >\n        >\n    >\n>;\n\n/*\n * GATT Tests\n */\nBOOST_FIXTURE_TEST_CASE( service_discoverable_by_uuid, gatt_procedures< bootloader_server > )\n{\n    BOOST_CHECK_NE(\n        ( discover_primary_service_by_uuid< bluetoe::bootloader::service_uuid >() ),\n        discovered_service( 0, 0 ) );\n}\n\ntemplate < class Server >\nstruct services_discovered : gatt_procedures< Server, test_mtu_size >\n{\n    services_discovered()\n        : service( this->template discover_primary_service_by_uuid< bluetoe::bootloader::service_uuid >() )\n    {\n        BOOST_REQUIRE_NE( service, discovered_service() );\n    }\n\n    const discovered_service service;\n};\n\nBOOST_FIXTURE_TEST_CASE( characteristics_are_discoverable, services_discovered< bootloader_server > )\n{\n    BOOST_CHECK_NE(\n        discover_characteristic_by_uuid< bluetoe::bootloader::control_point_uuid >( service ),\n        discovered_characteristic() );\n\n    BOOST_CHECK_NE(\n        discover_characteristic_by_uuid< bluetoe::bootloader::data_uuid >( service ),\n        discovered_characteristic() );\n\n    BOOST_CHECK_NE(\n        discover_characteristic_by_uuid< bluetoe::bootloader::progress_uuid >( service ),\n        discovered_characteristic() );\n}\n\ntemplate < class Server >\nstruct all_discovered : services_discovered< Server >\n{\n    all_discovered()\n        : cp_char( this->template discover_characteristic_by_uuid< bluetoe::bootloader::control_point_uuid >( this->service ) )\n        , data_char( this->template discover_characteristic_by_uuid< bluetoe::bootloader::data_uuid >( this->service ) )\n        , progress_char( this->template discover_characteristic_by_uuid< bluetoe::bootloader::progress_uuid >( this->service ) )\n    {\n        BOOST_REQUIRE_NE( cp_char, discovered_characteristic() );\n        BOOST_REQUIRE_NE( data_char, discovered_characteristic() );\n        BOOST_REQUIRE_NE( progress_char, discovered_characteristic() );\n    }\n\n    const discovered_characteristic cp_char;\n    const discovered_characteristic data_char;\n    const discovered_characteristic progress_char;\n};\n\nBOOST_FIXTURE_TEST_CASE( control_point_properties, all_discovered< bootloader_server > )\n{\n    BOOST_CHECK_EQUAL( cp_char.properties, 0x1c );\n}\n\nBOOST_FIXTURE_TEST_CASE( data_char_properties, all_discovered< bootloader_server > )\n{\n    BOOST_CHECK_EQUAL( data_char.properties, 0x2c );\n}\n\nBOOST_FIXTURE_TEST_CASE( progress_char_properties, all_discovered< bootloader_server > )\n{\n    BOOST_CHECK_EQUAL( progress_char.properties, 0x10 );\n}\n\nBOOST_FIXTURE_TEST_CASE( control_point_subscribe_for_notifications, all_discovered< bootloader_server > )\n{\n    const auto cccd = discover_cccd( cp_char );\n    BOOST_CHECK_NE( cccd, discovered_characteristic_descriptor() );\n\n    l2cap_input({\n        0x12, low( cccd.handle ), high( cccd.handle ),\n        0x01, 0x00\n    });\n\n    expected_result( { 0x13 } );\n}\n\nBOOST_FIXTURE_TEST_CASE( progress_subscribe_for_notifications, all_discovered< bootloader_server > )\n{\n    const auto cccd = discover_cccd( progress_char );\n    BOOST_CHECK_NE( cccd, discovered_characteristic_descriptor() );\n\n    l2cap_input({\n        0x12, low( cccd.handle ), high( cccd.handle ),\n        0x01, 0x00\n    });\n\n    expected_result( { 0x13 } );\n}\n\ntemplate < class Server >\nstruct all_discovered_and_subscribed : all_discovered< Server >\n{\n    all_discovered_and_subscribed()\n        : cp_cccd( this->discover_cccd( this->cp_char ) )\n        , progress_cccd( this->discover_cccd( this->progress_char ) )\n        , data_cccd( this->discover_cccd( this->data_char ) )\n    {\n        this->l2cap_input({\n            0x12, this->low( cp_cccd.handle ), this->high( cp_cccd.handle ),\n            0x01, 0x00\n        });\n        this->l2cap_input({\n            0x12, this->low( progress_cccd.handle ), this->high( progress_cccd.handle ),\n            0x01, 0x00\n        });\n        this->l2cap_input({\n            0x12, this->low( data_cccd.handle ), this->high( data_cccd.handle ),\n            0x02, 0x00\n        });\n    }\n\n    void add_ptr( std::vector< std::uint8_t >& v, std::uintptr_t p )\n    {\n        for ( int i = 0; i != sizeof( p ); ++i )\n        {\n            v.push_back( p & 0xff );\n            p = p >> 8;\n        }\n    }\n\n    const discovered_characteristic_descriptor    cp_cccd;\n    const discovered_characteristic_descriptor    progress_cccd;\n    const discovered_characteristic_descriptor    data_cccd;\n};\n\n/*\n * Get Version\n */\nBOOST_FIXTURE_TEST_CASE( get_version, all_discovered_and_subscribed< bootloader_server > )\n{\n    l2cap_input( {\n        0x12, low( cp_char.value_handle ), high( cp_char.value_handle ),\n        0x00 }, connection );\n    expected_result( { 0x13 } );\n\n    expected_output( notification, {\n        0x1b, low( cp_char.value_handle ), high( cp_char.value_handle ),    // notification\n        0x00,                                                               // response code\n        0x47, 0x11                                                          // version as given by handler::get_version()\n    } );\n}\n\n/*\n * Get CRC\n */\nBOOST_FIXTURE_TEST_CASE( get_crc, all_discovered_and_subscribed< bootloader_server > )\n{\n    std::vector< std::uint8_t > input = {\n        0x12, low( cp_char.value_handle ), high( cp_char.value_handle ),\n        0x01 };\n\n    add_ptr( input, 0x1000 );\n    add_ptr( input, 0x1002 );\n\n    l2cap_input( input, connection );\n\n    expected_result( { 0x13 } );\n\n    const std::uint32_t expected_checksum = device_memory[ 0 ] + device_memory[ 1 ];\n\n    expected_output( notification, {\n        0x1b, low( cp_char.value_handle ), high( cp_char.value_handle ),    // notification\n        0x01,                                                               // response code\n        static_cast< std::uint8_t >( expected_checksum & 0xff ),\n        static_cast< std::uint8_t >( ( expected_checksum >> 8 ) & 0xff ), 0x00, 0x00\n    } );\n}\n\nBOOST_FIXTURE_TEST_CASE( get_crc_wrong_addresses, all_discovered_and_subscribed< bootloader_server > )\n{\n    std::vector< std::uint8_t > input = {\n        0x12, low( cp_char.value_handle ), high( cp_char.value_handle ),\n        0x01 };\n\n    add_ptr( input, 0x1002 );\n    add_ptr( input, 0x1000 );\n\n    l2cap_input( input, connection );\n\n    expected_result( {\n        0x01, 0x12,\n        low( cp_char.value_handle ), high( cp_char.value_handle ),\n        0x07 } );\n\n    BOOST_CHECK( !notification.valid() );\n}\n\nBOOST_FIXTURE_TEST_CASE( get_crc_start_address_out_of_range, all_discovered_and_subscribed< bootloader_server > )\n{\n    std::vector< std::uint8_t > input = {\n        0x12, low( cp_char.value_handle ), high( cp_char.value_handle ),\n        0x01 };\n\n    add_ptr( input, 0x0fff );\n    add_ptr( input, 0x1002 );\n\n    l2cap_input( input, connection );\n\n    expected_result( {\n        0x01, 0x12,\n        low( cp_char.value_handle ), high( cp_char.value_handle ),\n        0x07 } );\n\n    BOOST_CHECK( !notification.valid() );\n}\n\nBOOST_FIXTURE_TEST_CASE( get_crc_end_address_out_of_range, all_discovered_and_subscribed< bootloader_server > )\n{\n    std::vector< std::uint8_t > input = {\n        0x12, low( cp_char.value_handle ), high( cp_char.value_handle ),\n        0x01 };\n\n    add_ptr( input, 0x1000 );\n    add_ptr( input, 0x1401 );\n\n    l2cap_input( input, connection );\n\n    expected_result( {\n        0x01, 0x12,\n        low( cp_char.value_handle ), high( cp_char.value_handle ),\n        0x07 } );\n\n    BOOST_CHECK( !notification.valid() );\n}\n\nBOOST_FIXTURE_TEST_CASE( get_crc_end_full_range, all_discovered_and_subscribed< bootloader_server > )\n{\n    std::vector< std::uint8_t > input = {\n        0x12, low( cp_char.value_handle ), high( cp_char.value_handle ),\n        0x01 };\n\n    add_ptr( input, 0x1000 );\n    add_ptr( input, 0x1400 );\n\n    l2cap_input( input, connection );\n\n    expected_result( { 0x13 } );\n\n    BOOST_CHECK( notification.valid() );\n}\n\nBOOST_FIXTURE_TEST_CASE( get_crc_over_different_out_of_range, all_discovered_and_subscribed< bootloader_server > )\n{\n    std::vector< std::uint8_t > input = {\n        0x12, low( cp_char.value_handle ), high( cp_char.value_handle ),\n        0x01 };\n\n    add_ptr( input, 0x1000 );\n    add_ptr( input, 0x2000 );\n\n    l2cap_input( input, connection );\n\n    expected_result( {\n        0x01, 0x12,\n        low( cp_char.value_handle ), high( cp_char.value_handle ),\n        0x07 } );\n\n    BOOST_CHECK( !notification.valid() );\n}\n\nBOOST_FIXTURE_TEST_CASE( public_checksum32_is_called, all_discovered_and_subscribed< bootloader_server > )\n{\n    report_fixed_public_crc( 0x12345678 );\n\n    std::vector< std::uint8_t > input = {\n        0x12, low( cp_char.value_handle ), high( cp_char.value_handle ),\n        0x01 };\n\n    add_ptr( input, 0x1000 );\n    add_ptr( input, 0x1002 );\n\n    l2cap_input( input, connection );\n\n    expected_result( { 0x13 } );\n\n    expected_output( notification, {\n        0x1b, low( cp_char.value_handle ), high( cp_char.value_handle ),    // notification\n        0x01,                                                               // response code\n        0x78, 0x56, 0x34, 0x12\n    } );\n}\n\n/*\n * Get Sizes\n */\nBOOST_FIXTURE_TEST_CASE( get_sizes, all_discovered_and_subscribed< bootloader_server > )\n{\n    l2cap_input( {\n        0x12, low( cp_char.value_handle ), high( cp_char.value_handle ),\n        0x02 }, connection );\n\n    expected_result( { 0x13 } );\n\n    expected_output( notification, {\n        0x1b, low( cp_char.value_handle ), high( cp_char.value_handle ),    // notification\n        0x02,                                                               // response code\n        sizeof(std::uint8_t*),                                              // Address size\n        block_size & 0xff, block_size >> 8, 0, 0,                           // Size of a Page\n        0x02, 0, 0, 0                                                       // Number of pages the bootloader can buffer\n    } );\n}\n\n/*\n * Start Flash\n */\nBOOST_FIXTURE_TEST_CASE( flash_address_wrong_ptr_size, all_discovered_and_subscribed< bootloader_server > )\n{\n    l2cap_input( {\n        0x12, low( cp_char.value_handle ), high( cp_char.value_handle ),\n        0x03, 0x12 }, connection );\n\n    expected_result( {\n        0x01, 0x12, low( cp_char.value_handle ), high( cp_char.value_handle ),\n        0x0d } ); // Invalid Attribute Value Length\n\n    // no notification expected\n    BOOST_CHECK( !notification.valid() );\n}\n\nBOOST_FIXTURE_TEST_CASE( flash_address_out_of_range, all_discovered_and_subscribed< bootloader_server > )\n{\n    std::vector< std::uint8_t > input = {\n        0x12, low( cp_char.value_handle ), high( cp_char.value_handle ),\n        0x03 };\n\n    add_ptr( input, 0x0 );\n    l2cap_input( input, connection );\n\n    expected_result( {\n        0x01, 0x12, low( cp_char.value_handle ), high( cp_char.value_handle ),\n        0x07 } ); // invalid Offset\n\n    // no notification expected\n    BOOST_CHECK( !notification.valid() );\n}\n\nBOOST_FIXTURE_TEST_CASE( flash_address, all_discovered_and_subscribed< bootloader_server > )\n{\n    std::vector< std::uint8_t > input = {\n        0x12, low( cp_char.value_handle ), high( cp_char.value_handle ),\n        0x03 };\n\n    add_ptr( input, 0x1002 );\n    l2cap_input( input, connection );\n\n    expected_result( { 0x13 } );\n\n    expected_output( notification, {\n        0x1b, low( cp_char.value_handle ), high( cp_char.value_handle ),    // notification\n        0x03,                                                               // response code\n        0x17,                                                               // MTU\n        0x12, 0x00, 0x00, 0x00                                              // checksum over start address = 0x10 + 0x02\n    } );\n}\n\n/*\n * Flush\n */\nBOOST_FIXTURE_TEST_CASE( flush_when_not_in_flash_mode, all_discovered_and_subscribed< bootloader_server > )\n{\n    check_error_response( {\n        0x12, low( cp_char.value_handle ), high( cp_char.value_handle ),\n        0x05 },\n        0x12, cp_char.value_handle, 0x82 );\n}\n\ntemplate < class Server, std::size_t StartAddress = flash_start_addr >\nstruct start_flash : all_discovered_and_subscribed< Server >\n{\n    start_flash()\n        : written_memory( this->original_device_memory )\n    {\n        start_flash_procedure( StartAddress );\n    }\n\n    void start_flash_procedure( std::size_t start_address )\n    {\n        address = start_address;\n        std::vector< std::uint8_t > input = {\n            0x12, this->low( this->cp_char.value_handle ), this->high( this->cp_char.value_handle ),\n            0x03 };\n\n        this->add_ptr( input, start_address );\n\n        this->l2cap_input( input, this->connection );\n\n        this->expected_result( { 0x13 } );\n\n        const auto queued_notification = this->connection.dequeue_indication_or_confirmation();\n        BOOST_REQUIRE( queued_notification.first == bluetoe::details::notification_queue_entry_type::notification );\n    }\n\n    void write_to_data_char( const std::initializer_list< std::uint8_t > data )\n    {\n        write_to_data_char( data.begin(), data.size() );\n    }\n\n    void write_to_data_char( const std::uint8_t* data, std::size_t size )\n    {\n        while ( size )\n        {\n            std::size_t transfer_size = std::min( test_mtu_size, size );\n\n            std::vector< std::uint8_t > output = {\n                0x12, this->low( this->data_char.value_handle ), this->high( this->data_char.value_handle )\n            };\n            output.insert( output.end(), data, data + transfer_size );\n\n            this->l2cap_input( output, this->connection );\n            this->expected_result( { 0x13 } );\n            size -= transfer_size;\n\n            // use at() not std::copy to find runtime errors\n            for ( ; transfer_size; ++data, --transfer_size, ++address )\n            {\n                written_memory.at( address - flash_start_addr ) = *data;\n            }\n        }\n\n    }\n\n    void write_random_to_data_char( std::size_t size )\n    {\n        std::vector< std::uint8_t > random_numbers;\n\n        for (; size; --size )\n            random_numbers.push_back( random_() & 0xff );\n\n        write_to_data_char( &random_numbers[ 0 ], random_numbers.size() );\n    }\n\n    std::vector< std::uint8_t > written_memory;\n    std::size_t                 address;\n    std::mt19937                random_;\n};\n\ntemplate < class Server >\nstruct write_3_bytes_at_the_beginning_of_the_flash : start_flash< Server >\n{\n    write_3_bytes_at_the_beginning_of_the_flash()\n    {\n        this->l2cap_input( {\n            0x12, this->low( this->data_char.value_handle ), this->high( this->data_char.value_handle ),\n            0x0a, 0x0b, 0x0c\n        }, this->connection );\n\n        this->expected_result( { 0x13 } );\n    }\n};\n\nBOOST_FIXTURE_TEST_CASE( flush_notification_after_flashing, write_3_bytes_at_the_beginning_of_the_flash< bootloader_server > )\n{\n    l2cap_input( {\n        0x12, low( cp_char.value_handle ), high( cp_char.value_handle ),\n        0x05\n    }, connection );\n\n    expected_result( { 0x13 } );\n\n    const std::uint32_t expected_checksum = checksum32( flash_start_addr )\n        + 0x0a + 0x0b + 0x0c;\n\n    expected_output< bluetoe::bootloader::control_point_uuid >( {\n        0x1b, low( cp_char.value_handle ), high( cp_char.value_handle ),\n        0x05,\n        static_cast< std::uint8_t >( expected_checksum & 0xff ),               // checksum\n        static_cast< std::uint8_t >( ( expected_checksum >> 8 ) & 0xff ),\n        static_cast< std::uint8_t >( ( expected_checksum >> 16 ) & 0xff ),\n        static_cast< std::uint8_t >( ( expected_checksum >> 24 ) & 0xff ),\n        0x00, 0x00,                             // consecutive number\n    } );\n\n    // the flashed memory should be a whole page and the content should be equal to the original content\n    // exept for the 3 bytes, written at the beginning\n    BOOST_CHECK_EQUAL( start_flash_address, flash_start_addr );\n\n    static constexpr std::uint8_t expected_flash_content[] = { 0x0a, 0x0b, 0x0c };\n\n    std::copy( std::begin( expected_flash_content ), std::end( expected_flash_content ),\n        original_device_memory.begin() );\n\n    BOOST_CHECK_EQUAL( start_flash_content.size(), block_size );\n    BOOST_CHECK_EQUAL_COLLECTIONS( original_device_memory.begin(), original_device_memory.begin() + start_flash_content.size(),\n        start_flash_content.begin(), start_flash_content.end() );\n\n    // now, when signaling the end of the flash process, we get a notification\n    end_flash( *this );\n\n    expected_output< bluetoe::bootloader::progress_uuid >( {\n        0x1b, low( progress_char.value_handle ), high( progress_char.value_handle ),\n        static_cast< std::uint8_t >( expected_checksum & 0xff ),               // checksum\n        static_cast< std::uint8_t >( ( expected_checksum >> 8 ) & 0xff ),\n        static_cast< std::uint8_t >( ( expected_checksum >> 16 ) & 0xff ),\n        static_cast< std::uint8_t >( ( expected_checksum >> 24 ) & 0xff ),\n        0x00, 0x00,                             // consecutive number\n        0x17                                    // MTU\n   } );\n}\n\nBOOST_FIXTURE_TEST_CASE( write_next_block_after_flush_before_progress, write_3_bytes_at_the_beginning_of_the_flash< bootloader_server > )\n{\n    // flush\n    l2cap_input( {\n        0x12, low( cp_char.value_handle ), high( cp_char.value_handle ),\n        0x05\n    }, connection );\n\n    // external input should never leed to an assert\n    start_flash_procedure( flash_start_addr );\n}\n\nBOOST_FIXTURE_TEST_CASE( write_block_after_flush, write_3_bytes_at_the_beginning_of_the_flash< bootloader_server > )\n{\n    // flush\n    l2cap_input( {\n        0x12, low( cp_char.value_handle ), high( cp_char.value_handle ),\n        0x05\n    }, connection );\n\n    expected_result( { 0x13 } );\n\n    std::uint32_t expected_checksum = checksum32( flash_start_addr )\n        + 0x0a + 0x0b + 0x0c;\n\n    expected_output< bluetoe::bootloader::control_point_uuid >( {\n        0x1b, low( cp_char.value_handle ), high( cp_char.value_handle ),\n        0x05,\n        static_cast< std::uint8_t >( expected_checksum & 0xff ),               // checksum\n        static_cast< std::uint8_t >( ( expected_checksum >> 8 ) & 0xff ),\n        static_cast< std::uint8_t >( ( expected_checksum >> 16 ) & 0xff ),\n        static_cast< std::uint8_t >( ( expected_checksum >> 24 ) & 0xff ),\n        0x00, 0x00,                             // consecutive number\n    } );\n\n    // now, when signaling the end of the flash process, we get a notification\n    end_flash( *this );\n\n    expected_output< bluetoe::bootloader::progress_uuid >( {\n        0x1b, low( progress_char.value_handle ), high( progress_char.value_handle ),\n        static_cast< std::uint8_t >( expected_checksum & 0xff ),               // checksum\n        static_cast< std::uint8_t >( ( expected_checksum >> 8 ) & 0xff ),\n        static_cast< std::uint8_t >( ( expected_checksum >> 16 ) & 0xff ),\n        static_cast< std::uint8_t >( ( expected_checksum >> 24 ) & 0xff ),\n        0x00, 0x00,                             // consecutive number\n        0x17                                    // MTU\n   } );\n\n    // now a new block\n    start_flash_procedure( flash_start_addr );\n    write_random_to_data_char( block_size );\n    expected_checksum = checksum32( &device_memory[ 0 ], block_size, checksum32( flash_start_addr ) );\n\n    // now, when signaling the end of the flash process, we get a notification\n    end_flash( *this );\n\n    expected_output< bluetoe::bootloader::progress_uuid >( {\n        0x1b, low( progress_char.value_handle ), high( progress_char.value_handle ),\n        static_cast< std::uint8_t >( expected_checksum & 0xff ),               // checksum\n        static_cast< std::uint8_t >( ( expected_checksum >> 8 ) & 0xff ),\n        static_cast< std::uint8_t >( ( expected_checksum >> 16 ) & 0xff ),\n        static_cast< std::uint8_t >( ( expected_checksum >> 24 ) & 0xff ),\n        0x00, 0x00,                             // consecutive number\n        0x17                                    // MTU\n   } );\n}\n\n/*\n * Start\n */\nBOOST_FIXTURE_TEST_CASE( start_program, all_discovered_and_subscribed< bootloader_server > )\n{\n    std::vector< std::uint8_t > input = {\n        0x12, low( cp_char.value_handle ), high( cp_char.value_handle ),\n        0x06 };\n\n    add_ptr( input, 0xabcd1234 );\n    l2cap_input( input, connection );\n\n    BOOST_CHECK_EQUAL( start_program_called, 0xabcd1234 );\n}\n\n/*\n * Reset\n */\nBOOST_FIXTURE_TEST_CASE( reset_bootloader, all_discovered_and_subscribed< bootloader_server > )\n{\n    l2cap_input( {\n        0x12, low( cp_char.value_handle ), high( cp_char.value_handle ),\n        0x07\n    }, connection );\n\n    BOOST_CHECK( reset_called );\n}\n\nBOOST_AUTO_TEST_SUITE( flashing_data )\n\n    using write_at_250 = start_flash< bootloader_server, flash_start_addr + 250 >;\n    BOOST_FIXTURE_TEST_CASE( flash_data_at_end_of_block, write_at_250 )\n    {\n        write_to_data_char( { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 } );\n\n        BOOST_CHECK( this->connection.dequeue_indication_or_confirmation().first\n            == bluetoe::details::notification_queue_entry_type::empty );\n\n        // the first block must be completly written\n        BOOST_CHECK_EQUAL( start_flash_content.size(), block_size );\n        BOOST_CHECK_EQUAL( start_flash_address, flash_start_addr );\n\n        BOOST_CHECK_EQUAL_COLLECTIONS( written_memory.begin(), written_memory.begin() + block_size,\n            start_flash_content.begin(), start_flash_content.end() );\n\n        // now, when signaling the end of the flash process, we get a notification\n        end_flash( *this );\n\n        const std::uint32_t expected_checksum = checksum32( flash_start_addr + 250 )\n            + 0x01 + 0x02 + 0x03 + 0x04 + 0x05 + 0x06;\n\n        expected_output< bluetoe::bootloader::progress_uuid >( {\n            0x1b, low( progress_char.value_handle ), high( progress_char.value_handle ),\n            static_cast< std::uint8_t >( expected_checksum & 0xff ),               // checksum\n            static_cast< std::uint8_t >( ( expected_checksum >> 8 ) & 0xff ),\n            static_cast< std::uint8_t >( ( expected_checksum >> 16 ) & 0xff ),\n            static_cast< std::uint8_t >( ( expected_checksum >> 24 ) & 0xff ),\n            0x00, 0x00,                             // consecutive number\n            0x17                                    // MTU\n       } );\n    }\n\n    using write_at_250 = start_flash< bootloader_server, flash_start_addr + 250 >;\n    BOOST_FIXTURE_TEST_CASE( flash_data_over_the_end_of_a_block, write_at_250 )\n    {\n        write_to_data_char( { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 } );\n        write_random_to_data_char( block_size );\n\n        // now both buffers are filled\n        check_error_response( {\n            0x12, low( data_char.value_handle ), high( data_char.value_handle ),\n            0x07\n        }, 0x12, data_char.value_handle, 0x83 );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( flash_data_after_a_filled_block, start_flash< bootloader_server > )\n    {\n        write_random_to_data_char( block_size );\n        write_random_to_data_char( block_size - 1 );\n\n        // now, there is only room for a single byte\n        check_error_response( {\n            0x12, low( data_char.value_handle ), high( data_char.value_handle ),\n            0x07, 0x08\n        }, 0x12, data_char.value_handle, 0x83 );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( write_4_blocks, start_flash< bootloader_server > )\n    {\n        write_random_to_data_char( block_size );\n        write_random_to_data_char( block_size );\n\n        end_flash( *this );\n\n        const std::uint32_t expected_checksum =\n            checksum32( &written_memory[ 0 ], block_size, checksum32( flash_start_addr ) );\n\n        expected_output< bluetoe::bootloader::progress_uuid >( {\n            0x1b, low( progress_char.value_handle ), high( progress_char.value_handle ),\n            static_cast< std::uint8_t >( expected_checksum & 0xff ),               // checksum\n            static_cast< std::uint8_t >( ( expected_checksum >> 8 ) & 0xff ),\n            static_cast< std::uint8_t >( ( expected_checksum >> 16 ) & 0xff ),\n            static_cast< std::uint8_t >( ( expected_checksum >> 24 ) & 0xff ),\n            0x00, 0x00,                             // consecutive number\n            0x17                                    // MTU\n        } );\n\n        write_random_to_data_char( block_size );\n        end_flash( *this );\n\n        const std::uint32_t expected_checksum_block2 =\n            checksum32( &written_memory[ 1 * block_size ], block_size, expected_checksum );\n\n        expected_output< bluetoe::bootloader::progress_uuid >( {\n            0x1b, low( progress_char.value_handle ), high( progress_char.value_handle ),\n            static_cast< std::uint8_t >( expected_checksum_block2 & 0xff ),               // checksum\n            static_cast< std::uint8_t >( ( expected_checksum_block2 >> 8 ) & 0xff ),\n            static_cast< std::uint8_t >( ( expected_checksum_block2 >> 16 ) & 0xff ),\n            static_cast< std::uint8_t >( ( expected_checksum_block2 >> 24 ) & 0xff ),\n            0x01, 0x00,                             // consecutive number\n            0x17                                    // MTU\n        } );\n\n        // last block to write\n        write_random_to_data_char( block_size );\n        end_flash( *this );\n\n        const std::uint32_t expected_checksum_block3 =\n            checksum32( &written_memory[ 2 * block_size ], block_size, expected_checksum_block2 );\n\n        expected_output< bluetoe::bootloader::progress_uuid >( {\n            0x1b, low( progress_char.value_handle ), high( progress_char.value_handle ),\n            static_cast< std::uint8_t >( expected_checksum_block3 & 0xff ),               // checksum\n            static_cast< std::uint8_t >( ( expected_checksum_block3 >> 8 ) & 0xff ),\n            static_cast< std::uint8_t >( ( expected_checksum_block3 >> 16 ) & 0xff ),\n            static_cast< std::uint8_t >( ( expected_checksum_block3 >> 24 ) & 0xff ),\n            0x02, 0x00,                             // consecutive number\n            0x17                                    // MTU\n        } );\n\n        end_flash( *this );\n\n        const std::uint32_t expected_checksum_block4 =\n            checksum32( &written_memory[ 3 * block_size ], block_size, expected_checksum_block3 );\n\n        expected_output< bluetoe::bootloader::progress_uuid >( {\n            0x1b, low( progress_char.value_handle ), high( progress_char.value_handle ),\n            static_cast< std::uint8_t >( expected_checksum_block4 & 0xff ),               // checksum\n            static_cast< std::uint8_t >( ( expected_checksum_block4 >> 8 ) & 0xff ),\n            static_cast< std::uint8_t >( ( expected_checksum_block4 >> 16 ) & 0xff ),\n            static_cast< std::uint8_t >( ( expected_checksum_block4 >> 24 ) & 0xff ),\n            0x03, 0x00,                             // consecutive number\n            0x17                                    // MTU\n        } );\n\n        BOOST_CHECK_EQUAL_COLLECTIONS(\n            written_memory.begin(), written_memory.end(),\n            device_memory.begin(), device_memory.end() );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( write_4_blocks_fast_flash, start_flash< bootloader_server > )\n    {\n        write_random_to_data_char( block_size );\n        end_flash( *this );\n\n        const std::uint32_t expected_checksum =\n            checksum32( &written_memory[ 0 ], block_size, checksum32( flash_start_addr ) );\n\n        expected_output< bluetoe::bootloader::progress_uuid >( {\n            0x1b, low( progress_char.value_handle ), high( progress_char.value_handle ),\n            static_cast< std::uint8_t >( expected_checksum & 0xff ),               // checksum\n            static_cast< std::uint8_t >( ( expected_checksum >> 8 ) & 0xff ),\n            static_cast< std::uint8_t >( ( expected_checksum >> 16 ) & 0xff ),\n            static_cast< std::uint8_t >( ( expected_checksum >> 24 ) & 0xff ),\n            0x00, 0x00,                             // consecutive number\n            0x17                                    // MTU\n        } );\n\n        write_random_to_data_char( block_size );\n        end_flash( *this );\n\n        const std::uint32_t expected_checksum_block2 =\n            checksum32( &written_memory[ 1 * block_size ], block_size, expected_checksum );\n\n        expected_output< bluetoe::bootloader::progress_uuid >( {\n            0x1b, low( progress_char.value_handle ), high( progress_char.value_handle ),\n            static_cast< std::uint8_t >( expected_checksum_block2 & 0xff ),               // checksum\n            static_cast< std::uint8_t >( ( expected_checksum_block2 >> 8 ) & 0xff ),\n            static_cast< std::uint8_t >( ( expected_checksum_block2 >> 16 ) & 0xff ),\n            static_cast< std::uint8_t >( ( expected_checksum_block2 >> 24 ) & 0xff ),\n            0x01, 0x00,                             // consecutive number\n            0x17                                    // MTU\n        } );\n\n        write_random_to_data_char( block_size );\n        end_flash( *this );\n\n        const std::uint32_t expected_checksum_block3 =\n            checksum32( &written_memory[ 2 * block_size ], block_size, expected_checksum_block2 );\n\n        expected_output< bluetoe::bootloader::progress_uuid >( {\n            0x1b, low( progress_char.value_handle ), high( progress_char.value_handle ),\n            static_cast< std::uint8_t >( expected_checksum_block3 & 0xff ),               // checksum\n            static_cast< std::uint8_t >( ( expected_checksum_block3 >> 8 ) & 0xff ),\n            static_cast< std::uint8_t >( ( expected_checksum_block3 >> 16 ) & 0xff ),\n            static_cast< std::uint8_t >( ( expected_checksum_block3 >> 24 ) & 0xff ),\n            0x02, 0x00,                             // consecutive number\n            0x17                                    // MTU\n        } );\n\n        write_random_to_data_char( block_size );\n        end_flash( *this );\n\n        const std::uint32_t expected_checksum_block4 =\n            checksum32( &written_memory[ 3 * block_size ], block_size, expected_checksum_block3 );\n\n        expected_output< bluetoe::bootloader::progress_uuid >( {\n            0x1b, low( progress_char.value_handle ), high( progress_char.value_handle ),\n            static_cast< std::uint8_t >( expected_checksum_block4 & 0xff ),               // checksum\n            static_cast< std::uint8_t >( ( expected_checksum_block4 >> 8 ) & 0xff ),\n            static_cast< std::uint8_t >( ( expected_checksum_block4 >> 16 ) & 0xff ),\n            static_cast< std::uint8_t >( ( expected_checksum_block4 >> 24 ) & 0xff ),\n            0x03, 0x00,                             // consecutive number\n            0x17                                    // MTU\n        } );\n\n        BOOST_CHECK_EQUAL_COLLECTIONS(\n            written_memory.begin(), written_memory.end(),\n            device_memory.begin(), device_memory.end() );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( write_4_blocks_over_block_ends, start_flash< bootloader_server > )\n    {\n        write_random_to_data_char( block_size + 4 );\n        end_flash( *this );\n\n        const std::uint32_t expected_checksum =\n            checksum32( &written_memory[ 0 ], block_size, checksum32( flash_start_addr ) );\n\n        expected_output< bluetoe::bootloader::progress_uuid >( {\n            0x1b, low( progress_char.value_handle ), high( progress_char.value_handle ),\n            static_cast< std::uint8_t >( expected_checksum & 0xff ),               // checksum\n            static_cast< std::uint8_t >( ( expected_checksum >> 8 ) & 0xff ),\n            static_cast< std::uint8_t >( ( expected_checksum >> 16 ) & 0xff ),\n            static_cast< std::uint8_t >( ( expected_checksum >> 24 ) & 0xff ),\n            0x00, 0x00,                             // consecutive number\n            0x17                                    // MTU\n        } );\n\n        write_random_to_data_char( block_size );\n        end_flash( *this );\n\n        const std::uint32_t expected_checksum_block2 =\n            checksum32( &written_memory[ 1 * block_size ], block_size, expected_checksum );\n\n        expected_output< bluetoe::bootloader::progress_uuid >( {\n            0x1b, low( progress_char.value_handle ), high( progress_char.value_handle ),\n            static_cast< std::uint8_t >( expected_checksum_block2 & 0xff ),               // checksum\n            static_cast< std::uint8_t >( ( expected_checksum_block2 >> 8 ) & 0xff ),\n            static_cast< std::uint8_t >( ( expected_checksum_block2 >> 16 ) & 0xff ),\n            static_cast< std::uint8_t >( ( expected_checksum_block2 >> 24 ) & 0xff ),\n            0x01, 0x00,                             // consecutive number\n            0x17                                    // MTU\n        } );\n\n        write_random_to_data_char( block_size );\n        end_flash( *this );\n\n        const std::uint32_t expected_checksum_block3 =\n            checksum32( &written_memory[ 2 * block_size ], block_size, expected_checksum_block2 );\n\n        expected_output< bluetoe::bootloader::progress_uuid >( {\n            0x1b, low( progress_char.value_handle ), high( progress_char.value_handle ),\n            static_cast< std::uint8_t >( expected_checksum_block3 & 0xff ),               // checksum\n            static_cast< std::uint8_t >( ( expected_checksum_block3 >> 8 ) & 0xff ),\n            static_cast< std::uint8_t >( ( expected_checksum_block3 >> 16 ) & 0xff ),\n            static_cast< std::uint8_t >( ( expected_checksum_block3 >> 24 ) & 0xff ),\n            0x02, 0x00,                             // consecutive number\n            0x17                                    // MTU\n        } );\n\n        write_random_to_data_char( block_size - 4 );\n        end_flash( *this );\n\n        const std::uint32_t expected_checksum_block4 =\n            checksum32( &written_memory[ 3 * block_size ], block_size, expected_checksum_block3 );\n\n        expected_output< bluetoe::bootloader::progress_uuid >( {\n            0x1b, low( progress_char.value_handle ), high( progress_char.value_handle ),\n            static_cast< std::uint8_t >( expected_checksum_block4 & 0xff ),               // checksum\n            static_cast< std::uint8_t >( ( expected_checksum_block4 >> 8 ) & 0xff ),\n            static_cast< std::uint8_t >( ( expected_checksum_block4 >> 16 ) & 0xff ),\n            static_cast< std::uint8_t >( ( expected_checksum_block4 >> 24 ) & 0xff ),\n            0x03, 0x00,                             // consecutive number\n            0x17                                    // MTU\n        } );\n\n        BOOST_CHECK_EQUAL_COLLECTIONS(\n            written_memory.begin(), written_memory.end(),\n            device_memory.begin(), device_memory.end() );\n    }\n\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE( stop_flash )\n\n    BOOST_FIXTURE_TEST_CASE( stop_flash, all_discovered_and_subscribed< bootloader_server > )\n    {\n         l2cap_input( {\n            0x12, low( cp_char.value_handle ), high( cp_char.value_handle ),\n            0x04 }, connection );\n\n        expected_result( { 0x13 } );\n\n        expected_output( notification, {\n            0x1b, low( cp_char.value_handle ), high( cp_char.value_handle ),\n            0x04 } );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( stop_flash_while_in_flash_mode, start_flash< bootloader_server > )\n    {\n        l2cap_input( {\n            0x12, low( cp_char.value_handle ), high( cp_char.value_handle ),\n            0x04 }, connection );\n\n        expected_result( { 0x13 } );\n\n        expected_output( notification, {\n            0x1b, low( cp_char.value_handle ), high( cp_char.value_handle ),\n            0x04 } );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( flashing_after_stopping, start_flash< bootloader_server > )\n    {\n        write_to_data_char( { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 } );\n\n        l2cap_input( {\n            0x12, low( cp_char.value_handle ), high( cp_char.value_handle ),\n            0x04 }, connection );\n\n        expected_result( { 0x13 } );\n        written_memory = original_device_memory;\n\n        start_flash_procedure( flash_start_addr + block_size / 2 );\n        write_random_to_data_char( block_size / 2 );\n        end_flash( *this );\n\n        const std::uint32_t expected_checksum =\n            checksum32( &written_memory[ block_size / 2 ], block_size / 2, checksum32( flash_start_addr + block_size / 2 ) );\n\n        expected_output< bluetoe::bootloader::progress_uuid >( {\n            0x1b, low( progress_char.value_handle ), high( progress_char.value_handle ),\n            static_cast< std::uint8_t >( expected_checksum & 0xff ),               // checksum\n            static_cast< std::uint8_t >( ( expected_checksum >> 8 ) & 0xff ),\n            static_cast< std::uint8_t >( ( expected_checksum >> 16 ) & 0xff ),\n            static_cast< std::uint8_t >( ( expected_checksum >> 24 ) & 0xff ),\n            0x00, 0x00,                             // consecutive number\n            0x17                                    // MTU\n        } );\n    }\n\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE( read_procedure )\n\n    BOOST_FIXTURE_TEST_CASE( read_range_without_error, all_discovered_and_subscribed< bootloader_server > )\n    {\n        std::vector< std::uint8_t > input = {\n            0x12, low( cp_char.value_handle ), high( cp_char.value_handle ),\n            0x08 };\n\n        add_ptr( input, 0x1000 );\n        add_ptr( input, 0x1020 );\n\n        l2cap_input( input, connection );\n\n        expected_result( { 0x13 } ); // write response\n\n        BOOST_CHECK( data_indication_requested() );\n        bootloader_data_indication( *this );\n\n        expected_output( notification, {\n            0x1d, low( data_char.value_handle ), high( data_char.value_handle ),// indication\n            0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,                     // MTU - 3 bytes of data\n            0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,\n            0x10, 0x11, 0x12, 0x13\n        } );\n\n        this->connection.indication_confirmed();\n\n        BOOST_CHECK( data_indication_requested() );\n        bootloader_data_indication( *this );\n\n        expected_output( notification, {\n            0x1d, low( data_char.value_handle ), high( data_char.value_handle ),// indication\n            0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,                     // remaining bytes\n            0x1c, 0x1d, 0x1e, 0x1f\n        } );\n\n        this->connection.indication_confirmed();\n\n        BOOST_CHECK( !data_indication_requested() );\n        BOOST_CHECK( control_point_notification_requested() );\n        bootloader_control_point_notification( *this );\n\n        const std::uint32_t expected_checksum = checksum32( &device_memory[ 0 ], 0x20, checksum32( 0x1000 ) );\n\n        expected_output( notification, {\n            0x1b, low( cp_char.value_handle ), high( cp_char.value_handle ), // notification\n            0x08,                                                            // response code\n            static_cast< std::uint8_t >( expected_checksum & 0xff ),         // checksum\n            static_cast< std::uint8_t >( ( expected_checksum >> 8 ) & 0xff ),\n            static_cast< std::uint8_t >( ( expected_checksum >> 16 ) & 0xff ),\n            static_cast< std::uint8_t >( ( expected_checksum >> 24 ) & 0xff ),\n            0x00                                                             // success\n        } );\n\n        BOOST_CHECK( !control_point_notification_requested() );\n        BOOST_CHECK( !data_indication_requested() );\n    }\n\n    BOOST_FIXTURE_TEST_CASE( read_out_of_range, all_discovered_and_subscribed< bootloader_server > )\n    {\n        std::vector< std::uint8_t > input = {\n            0x12, low( cp_char.value_handle ), high( cp_char.value_handle ),\n            0x08 };\n\n        add_ptr( input, 0x0000 );\n        add_ptr( input, 0x1020 );\n\n        l2cap_input( input, connection );\n\n        expected_result( {\n            0x01, 0x12, low( cp_char.value_handle ), high( cp_char.value_handle ),\n            0x07 } ); // invalid Offset\n    }\n\n    BOOST_FIXTURE_TEST_CASE( read_handler_reports_error, all_discovered_and_subscribed< bootloader_server > )\n    {\n        report_read_error( 1 );\n\n        std::vector< std::uint8_t > input = {\n            0x12, low( cp_char.value_handle ), high( cp_char.value_handle ),\n            0x08 };\n\n        add_ptr( input, 0x1000 );\n        add_ptr( input, 0x1020 );\n\n        l2cap_input( input, connection );\n\n        expected_result( { 0x13 } ); // write response\n\n        BOOST_CHECK( data_indication_requested() );\n        bootloader_data_indication( *this );\n\n        expected_output( notification, {\n            0x1d, low( data_char.value_handle ), high( data_char.value_handle ),// indication\n            0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,                     // MTU - 3 bytes of data\n            0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,\n            0x10, 0x11, 0x12, 0x13\n        } );\n\n        this->connection.indication_confirmed();\n\n        BOOST_CHECK( data_indication_requested() );\n        bootloader_data_indication( *this );\n\n        expected_output( notification, {\n            0x1d, low( data_char.value_handle ), high( data_char.value_handle ) // indication\n        } );\n\n        BOOST_CHECK( !data_indication_requested() );\n        BOOST_CHECK( control_point_notification_requested() );\n        bootloader_control_point_notification( *this );\n\n        const std::uint32_t expected_checksum = checksum32( &device_memory[ 0 ], 20, checksum32( 0x1000 ) );\n\n        expected_output( notification, {\n            0x1b, low( cp_char.value_handle ), high( cp_char.value_handle ), // notification\n            0x08,                                                            // response code\n            static_cast< std::uint8_t >( expected_checksum & 0xff ),         // checksum\n            static_cast< std::uint8_t >( ( expected_checksum >> 8 ) & 0xff ),\n            static_cast< std::uint8_t >( ( expected_checksum >> 16 ) & 0xff ),\n            static_cast< std::uint8_t >( ( expected_checksum >> 24 ) & 0xff ),\n            0x01                                                             // not_authorized\n        } );\n\n        BOOST_CHECK( !control_point_notification_requested() );\n        BOOST_CHECK( !data_indication_requested() );\n    }\n\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_FIXTURE_TEST_CASE( write_page_without_command, all_discovered_and_subscribed< bootloader_server > )\n{\n    check_error_response( {\n        0x12, low( data_char.value_handle ), high( data_char.value_handle ),\n        0x00, 0x01, 0x02, 0x03 },\n        0x12, data_char.value_handle, 0x80 );\n}\n"
  },
  {
    "path": "tests/services/cscs_tests.cpp",
    "content": "#define BOOST_TEST_MODULE\n#include <boost/test/included/unit_test.hpp>\n\n#include <bluetoe/services/csc.hpp>\n\n#include \"test_servers.hpp\"\n#include \"attribute_io.hpp\"\n\n\nclass data_handler\n{\npublic:\n    void next_time( std::uint16_t time, std::uint32_t wheel, std::uint16_t crank )\n    {\n        time_  = time;\n        wheel_ = wheel;\n        crank_ = crank;\n    }\n\n    std::uint32_t cumulative_wheel_revolutions() const\n    {\n        return wheel_;\n    }\n\n    /*\n     * cycling_speed_and_cadence_handler_prototype implementation\n     */\n    std::pair< std::uint32_t, std::uint16_t > cumulative_wheel_revolutions_and_time()\n    {\n        return std::pair< std::uint32_t, std::uint16_t >( wheel_, time_ );\n    }\n\n    std::pair< std::uint16_t, std::uint16_t > cumulative_crank_revolutions_and_time()\n    {\n        return std::pair< std::uint16_t, std::uint16_t >( crank_, time_ );\n    }\n\n    void set_cumulative_wheel_revolutions( std::uint32_t new_value )\n    {\n        wheel_ = new_value;\n    }\n\n\nprivate:\n    std::uint16_t time_;\n    std::uint32_t wheel_;\n    std::uint16_t crank_;\n};\n\ntypedef bluetoe::server<\n    bluetoe::cycling_speed_and_cadence<\n        bluetoe::sensor_location::top_of_shoe,\n        bluetoe::csc::wheel_revolution_data_supported,\n        bluetoe::csc::crank_revolution_data_supported,\n        bluetoe::csc::handler< data_handler >\n    >\n> csc_server;\n\ntemplate < typename SensorPosition >\nusing csc_server_with_sensorposition = bluetoe::server<\n    bluetoe::cycling_speed_and_cadence<\n        SensorPosition,\n        bluetoe::csc::wheel_revolution_data_supported,\n        bluetoe::csc::crank_revolution_data_supported,\n        bluetoe::csc::handler< data_handler >\n    >\n>;\n\ntypedef bluetoe::server<\n    bluetoe::cycling_speed_and_cadence<\n        bluetoe::sensor_location::top_of_shoe,\n        bluetoe::sensor_location::in_shoe,\n        bluetoe::sensor_location::hip,\n        bluetoe::csc::wheel_revolution_data_supported,\n        bluetoe::csc::crank_revolution_data_supported,\n        bluetoe::csc::handler< data_handler >\n    >\n> csc_server_with_multiple_sensor_locations;\n\ntypedef bluetoe::server<\n    bluetoe::cycling_speed_and_cadence<\n        // two sensor locations, to force the existence of the control point\n        bluetoe::sensor_location::top_of_shoe,\n        bluetoe::sensor_location::left_crank,\n        bluetoe::csc::crank_revolution_data_supported,\n        bluetoe::csc::handler< data_handler >\n    >\n> csc_crank_only_server;\n\ntypedef bluetoe::server<\n    bluetoe::cycling_speed_and_cadence<\n        bluetoe::sensor_location::top_of_shoe,\n        bluetoe::csc::wheel_revolution_data_supported,\n        bluetoe::csc::handler< data_handler >\n    >\n> csc_wheel_only_server;\n\nstatic std::uint8_t low( std::uint16_t h )\n{\n    return h & 0xff;\n}\n\nstatic std::uint8_t high( std::uint16_t h )\n{\n    return ( h >> 8 ) & 0xff;\n}\n\nstatic std::uint16_t uint16( const std::uint8_t* p )\n{\n    return *p | ( *( p + 1 ) << 8 );\n}\n\nstruct service_discover_base {\n    std::uint16_t service_starting_handle;\n    std::uint16_t service_ending_handle;\n};\n\ntemplate < class Server >\nstruct discover_primary_service : test::request_with_reponse< Server, 100u >, service_discover_base\n{\n    discover_primary_service()\n    {\n        // TheLowerTestersendsanATT_Find_By_Type_Value_Request(0x0001, 0xFFFF)\n        // to the IUT, with type set to «Primary Service» and Value set to «Cycling Speed and Cadence Service».\n        this->l2cap_input( {\n            0x06, 0x01, 0x00, 0xff, 0xff, 0x00, 0x28, 0x16, 0x18\n        });\n\n        BOOST_REQUIRE_EQUAL( this->response_size, 5u );\n\n        service_starting_handle = this->response[ 1 ] | ( this->response[ 2 ] << 8 );\n        service_ending_handle   = this->response[ 3 ] | ( this->response[ 4 ] << 8 );\n    }\n};\n\nBOOST_AUTO_TEST_SUITE( service_definition )\n\n    /*\n     * TP/SD/BV-01-C\n     */\n    BOOST_FIXTURE_TEST_CASE( service_definition_over_le_as_primary_service, discover_primary_service< csc_server > )\n    {\n        BOOST_CHECK_EQUAL( response[ 0 ], 0x07 );\n        BOOST_CHECK_LT( service_starting_handle, service_ending_handle );\n    }\n\n    typedef bluetoe::server<\n        bluetoe::no_gap_service_for_gatt_servers,\n        bluetoe::service<\n            bluetoe::service_uuid16< 0x1234 >,\n            bluetoe::include_service< bluetoe::csc::service_uuid >\n        >,\n        bluetoe::cycling_speed_and_cadence<\n            bluetoe::is_secondary_service,\n            bluetoe::csc::handler< data_handler >\n        >\n    > csc_secondary_server;\n\n    struct discover_secondary_service : test::request_with_reponse< csc_secondary_server, 100u >, service_discover_base\n    {\n        discover_secondary_service()\n        {\n            // If no instances of Cycling Speed and Cadence Service as a primary service are found, the Lower Tester\n            // performs the included services procedure by sending an ATT_Read_By_Type_ Request\n            // (0x0001, 0xFFFF) to the IUT, with type set to «Include».\n            l2cap_input( {\n                0x08, 0x01, 0x00, 0xff, 0xff, 0x02, 0x28\n            });\n\n            BOOST_REQUIRE_EQUAL( response_size, 10u );\n            BOOST_REQUIRE_EQUAL( response[ 0 ], 0x09 ); // opcode\n            BOOST_REQUIRE_EQUAL( response[ 1 ], 0x08 ); // length\n\n            service_starting_handle = response[ 4 ] | ( response[ 5 ] << 8 );\n            service_ending_handle   = response[ 6 ] | ( response[ 7 ] << 8 );\n        }\n    };\n\n    /*\n     * TP/SD/BV-01-C\n     */\n    BOOST_FIXTURE_TEST_CASE( service_definition_over_le_as_secondary_service, discover_secondary_service )\n    {\n        BOOST_CHECK_EQUAL( response[ 0 ], 0x09 );\n        BOOST_CHECK_LT( service_starting_handle, service_ending_handle );\n    }\n\nBOOST_AUTO_TEST_SUITE_END()\n\nstruct characteristic_declaration\n{\n    std::uint16_t   handle;\n    std::uint8_t    properties;\n    std::uint16_t   value_attribute_handle;\n    std::uint16_t   uuid;\n};\n\nstruct handle_uuid_pair\n{\n    std::uint16_t handle;\n    std::uint16_t uuid;\n};\n\ntemplate < class Server >\nstruct discover_all_characteristics : discover_primary_service< Server >\n{\n    discover_all_characteristics()\n    {\n        // read by type request\n        this->l2cap_input( {\n            0x08,\n            low( this->service_starting_handle ), high( this->service_starting_handle ),\n            low( this->service_ending_handle ), high( this->service_ending_handle ),\n            0x03, 0x28 // <<characteristic>>\n        });\n\n        BOOST_REQUIRE_EQUAL( this->response_size, std::size_t( 2 + 4 * 7 ) );\n        BOOST_REQUIRE_EQUAL( this->response[ 0 ], 0x09u ); // response opcode\n        BOOST_REQUIRE_EQUAL( this->response[ 1 ], 7u );    // handle + value length\n\n        csc_measurement  = parse_characteristic_declaration( &this->response[ 2 + 0 * 7 ] );\n        csc_feature      = parse_characteristic_declaration( &this->response[ 2 + 1 * 7 ] );\n        sensor_location  = parse_characteristic_declaration( &this->response[ 2 + 2 * 7 ] );\n        cs_control_point = parse_characteristic_declaration( &this->response[ 2 + 3 * 7 ] );\n    }\n\n    static characteristic_declaration parse_characteristic_declaration( const std::uint8_t* pos )\n    {\n        return characteristic_declaration{ uint16( pos ), *( pos + 2 ), uint16( pos + 3 ), uint16( pos + 5 ) };\n    }\n\n    characteristic_declaration csc_measurement;\n    characteristic_declaration csc_feature;\n    characteristic_declaration sensor_location;\n    characteristic_declaration cs_control_point;\n};\n\nBOOST_AUTO_TEST_SUITE( characteristic_declaration_tests )\n\n\n    /*\n     * TP/DEC/BV-01-C\n     */\n    BOOST_FIXTURE_TEST_CASE( csc_measurement_test, discover_all_characteristics< csc_server > )\n    {\n        BOOST_CHECK_EQUAL( csc_measurement.properties, 0x10 );\n        BOOST_CHECK_EQUAL( csc_measurement.uuid, 0x2A5B );\n    }\n\n    /*\n     * TP/DEC/BV-02-C\n     */\n    BOOST_FIXTURE_TEST_CASE( csc_feature_test, discover_all_characteristics< csc_server > )\n    {\n        BOOST_CHECK_EQUAL( csc_feature.properties, 0x02 );\n        BOOST_CHECK_EQUAL( csc_feature.uuid, 0x2A5C );\n    }\n\n    /*\n     * TP/DEC/BV-03-C\n     */\n    BOOST_FIXTURE_TEST_CASE( sensor_location_test, discover_all_characteristics< csc_server > )\n    {\n        BOOST_CHECK_EQUAL( sensor_location.properties, 0x02 );\n        BOOST_CHECK_EQUAL( sensor_location.uuid, 0x2A5D );\n    }\n\n    /*\n     * TP/DEC/BV-04-C\n     */\n    BOOST_FIXTURE_TEST_CASE( sc_control_point_test, discover_all_characteristics< csc_server > )\n    {\n        BOOST_CHECK_EQUAL( cs_control_point.properties, 0x28 );\n        BOOST_CHECK_EQUAL( cs_control_point.uuid, 0x2A55 );\n    }\n\nBOOST_AUTO_TEST_SUITE_END()\n\ntemplate < class Server >\nstruct discover_all_descriptors : discover_all_characteristics< Server >\n{\n\n    discover_all_descriptors()\n    {\n        csc_measurement_client_configuration = find_client_characteristic_configuration(\n            this->csc_measurement.value_attribute_handle + 1, this->csc_feature.handle - 1);\n        sc_control_point_client_configuration = find_client_characteristic_configuration(\n            this->cs_control_point.value_attribute_handle + 1, this->service_ending_handle );\n    }\n\n    std::vector< handle_uuid_pair > find_information_request( std::uint16_t start_handle, std::uint16_t end_handle )\n    {\n        this->l2cap_input({\n            // Find information request\n            0x04,\n            low( start_handle ),\n            high( start_handle ),\n            low( end_handle ),\n            high( end_handle )\n        });\n\n        BOOST_REQUIRE_EQUAL( this->response[ 0 ], 0x05 ); // response opcode\n        BOOST_REQUIRE_EQUAL( this->response[ 1 ], 0x01 ); // Format\n        BOOST_REQUIRE_EQUAL( ( this->response_size - 2 ) % 4, 0u );\n\n        std::vector< handle_uuid_pair > result;\n        for ( const std::uint8_t* p = &this->response[ 2 ]; p != this->begin() + this->response_size; p += 4 )\n        {\n            result.push_back( handle_uuid_pair{ uint16( p ), uint16( p + 2 ) } );\n        }\n\n        return result;\n    }\n\n    handle_uuid_pair find_client_characteristic_configuration( std::uint16_t start_handle, std::uint16_t end_handle )\n    {\n        const auto descriptors = this->find_information_request( start_handle, end_handle );\n\n        const auto pos = std::find_if( descriptors.begin(), descriptors.end(),\n            []( handle_uuid_pair b ) -> bool {\n                return b.uuid == 0x2902;\n            });\n\n        BOOST_REQUIRE( pos != descriptors.end() );\n        return *pos;\n    }\n\n    std::vector< std::uint8_t > att_read( std::uint16_t handle )\n    {\n        this->l2cap_input({\n            0x0a, low( handle ), high( handle )\n        });\n\n        BOOST_REQUIRE_EQUAL( this->response[ 0 ], 0x0b ); // response opcode\n        BOOST_REQUIRE_GT( this->response_size, 1u );\n\n        return std::vector< std::uint8_t >( this->begin() + 1, this->begin() + this->response_size );\n    }\n\n    handle_uuid_pair csc_measurement_client_configuration;\n    handle_uuid_pair sc_control_point_client_configuration;\n};\n\nBOOST_AUTO_TEST_SUITE( characteristic_descriptors_tests )\n\n    /*\n     * TP/DES/BV-01-C\n     */\n    BOOST_FIXTURE_TEST_CASE( csc_measurement_client_characteristic_configuration_descriptor, discover_all_descriptors< csc_server > )\n    {\n        const auto value = att_read( csc_measurement_client_configuration.handle );\n\n        BOOST_CHECK_EQUAL( value.size(), 2u );\n        const std::uint16_t config_value = uint16( &value[ 0 ] );\n\n        BOOST_CHECK( config_value == 0x0000 || config_value == 0x0001 );\n    }\n\n    /*\n     * TP/DES/BV-02-C\n     */\n    BOOST_FIXTURE_TEST_CASE( sc_control_point_client_characteristic_configuration_descriptor, discover_all_descriptors< csc_server > )\n    {\n        const auto value = att_read( sc_control_point_client_configuration.handle );\n\n        BOOST_CHECK_EQUAL( value.size(), 2u );\n        const std::uint16_t config_value = uint16( &value[ 0 ] );\n\n        BOOST_CHECK( config_value == 0x0000 || config_value == 0x0002 );\n    }\n\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE( characteristic_read_value_test_cases )\n\n    /*\n     * TP/CR/BV-01-C\n     */\n    BOOST_FIXTURE_TEST_CASE( csc_feature_test, discover_all_descriptors< csc_server > )\n    {\n        l2cap_input({\n            0x0A, low( csc_feature.value_attribute_handle ), high( csc_feature.value_attribute_handle )\n        });\n\n        BOOST_CHECK_EQUAL( response[ 0 ], 0x0b ); // response opcode\n\n        // 2 octets with RFU bits set to 0.\n        BOOST_CHECK_EQUAL( response_size, 3u );\n        std::uint16_t value = uint16( &response[ 1 ] );\n        BOOST_CHECK_EQUAL( value & 0xFFF8, 0 );\n    }\n\n    /*\n     * TP/CR/BV-02-C\n     */\n    BOOST_FIXTURE_TEST_CASE( sensor_location_test, discover_all_descriptors< csc_server > )\n    {\n        l2cap_input({\n            0x0A, low( sensor_location.value_attribute_handle ), high( sensor_location.value_attribute_handle )\n        });\n\n        BOOST_CHECK_EQUAL( response[ 0 ], 0x0b ); // response opcode\n\n        // 1 octet with value other than RFU range.\n        BOOST_CHECK_EQUAL( response_size, 2u );\n        BOOST_CHECK_LT( response[ 1 ], 15 );\n    }\n\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE( configure_indication_and_notification )\n\n    template < typename Fixture >\n    void reset_handle( Fixture& fixture, uint16_t handle )\n    {\n        fixture.l2cap_input({\n            0x12,\n            low( handle ), high( handle ),\n            0x00, 0x00\n        });\n\n        BOOST_CHECK_EQUAL( fixture.response[ 0 ], 0x13 ); // response opcode\n    }\n\n    /*\n     * TP/CON/BV-01-C\n     */\n    BOOST_FIXTURE_TEST_CASE( csc_measurement_test, discover_all_descriptors< csc_server > )\n    {\n        reset_handle( *this, csc_measurement_client_configuration.handle );\n\n        l2cap_input({\n            0x12,\n            low( csc_measurement_client_configuration.handle ), high( csc_measurement_client_configuration.handle ),\n            0x01, 0x00\n        });\n\n        expected_result({ 0x13 });\n\n        // The Lower Tester reads the value of the client characteristic configuration descriptor.\n        l2cap_input({\n            0x0a,\n            low( csc_measurement_client_configuration.handle ), high( csc_measurement_client_configuration.handle ),\n        });\n\n        expected_result({\n            0x0b, 0x01, 0x00\n        });\n    }\n\n    /*\n     * TP/CON/BV-02-C\n     */\n    BOOST_FIXTURE_TEST_CASE( sc_control_point_test, discover_all_descriptors< csc_server > )\n    {\n        reset_handle( *this, sc_control_point_client_configuration.handle );\n\n        l2cap_input({\n            0x12,\n            low( sc_control_point_client_configuration.handle ), high( sc_control_point_client_configuration.handle ),\n            0x02, 0x00\n        });\n\n        expected_result({ 0x13 });\n\n        // The Lower Tester reads the value of the client characteristic configuration descriptor.\n        l2cap_input({\n            0x0a,\n            low( sc_control_point_client_configuration.handle ), high( sc_control_point_client_configuration.handle ),\n        });\n\n        expected_result({\n            0x0b, 0x02, 0x00\n        });\n    }\n\nBOOST_AUTO_TEST_SUITE_END()\n\ntemplate < class Server >\nstruct discover_and_configure_all_descriptor : discover_all_descriptors< Server >\n{\n    discover_and_configure_all_descriptor()\n    {\n        this->l2cap_input({\n            0x12,\n            low( this->csc_measurement_client_configuration.handle ),\n            high( this->csc_measurement_client_configuration.handle ),\n            0x01, 0x00\n        });\n        this->expected_result({ 0x13 });\n\n        this->l2cap_input({\n            0x12,\n            low( this->sc_control_point_client_configuration.handle ),\n            high( this->sc_control_point_client_configuration.handle ),\n            0x02, 0x00\n        });\n        this->expected_result({ 0x13 });\n    }\n};\n\nBOOST_AUTO_TEST_SUITE( characteristic_notification )\n\n    /*\n     * TP/CN/BV-01-C\n     * TP/CN/BV-02-C\n     * TP/CN/BV-03-C\n     * TP/CN/BV-04-C\n     */\n    BOOST_FIXTURE_TEST_CASE( csc_measurement_notifications__wheel_revolution_data, discover_and_configure_all_descriptor< csc_server > )\n    {\n        // update values\n        next_time( 0x1234, 0x23456789, 0x3456 );\n        notify_timed_update( *static_cast< discover_and_configure_all_descriptor< csc_server >::server* >( this ) );\n\n        // notification?\n        BOOST_REQUIRE( notification.valid() );\n        BOOST_CHECK_EQUAL( notification_type, bluetoe::details::notification_type::notification );\n\n        // lets generate a notification pdu\n        expected_output( notification, {\n            0x1b, 0x03, 0x00,                   // indication < handle >\n            0x03,                               // flags\n            0x89, 0x67, 0x45, 0x23, 0x34, 0x12, // wheel and time\n            0x56, 0x34, 0x34, 0x12              // crank and time\n        });\n    }\n\n    BOOST_FIXTURE_TEST_CASE( only_crank_mesurement, discover_and_configure_all_descriptor< csc_crank_only_server > )\n    {\n        // update values\n        next_time( 0x1234, 0x23456789, 0x3456 );\n        notify_timed_update( *static_cast< discover_and_configure_all_descriptor< csc_crank_only_server >::server* >( this ) );\n\n        // notification?\n        BOOST_REQUIRE( notification.valid() );\n        BOOST_CHECK_EQUAL( int( notification_type ), int( bluetoe::details::notification_type::notification ) );\n\n        // lets generate a notification pdu\n        expected_output( notification, {\n            0x1b, 0x03, 0x00,                   // indication < handle >\n            0x02,                               // flags\n            0x56, 0x34, 0x34, 0x12              // crank and time\n        });\n    }\n\n    BOOST_FIXTURE_TEST_CASE( only_wheel_mesurement, discover_and_configure_all_descriptor< csc_wheel_only_server > )\n    {\n        // update values\n        next_time( 0x1234, 0x23456789, 0x3456 );\n        notify_timed_update( *this );\n\n        // notification?\n        BOOST_REQUIRE( notification.valid() );\n        BOOST_CHECK_EQUAL( int( notification_type ), int( bluetoe::details::notification_type::notification ) );\n\n        // lets generate a notification pdu\n        expected_output( notification, {\n            0x1b, 0x03, 0x00,                   // indication < handle >\n            0x01,                               // flags\n            0x89, 0x67, 0x45, 0x23, 0x34, 0x12  // wheel and time\n        });\n    }\n\n\nBOOST_AUTO_TEST_SUITE_END()\n\ntemplate < class Server >\nvoid check_cp_response( Server& server, std::initializer_list< std::uint8_t > response )\n{\n    BOOST_REQUIRE( server.notification.valid() );\n    BOOST_CHECK_EQUAL( int( server.notification_type ), int( bluetoe::details::notification_type::indication ) );\n\n    std::vector< std::uint8_t > expected = {\n        0x1d,\n        low( server.cs_control_point.value_attribute_handle ),\n        high( server.cs_control_point.value_attribute_handle ) };\n\n    expected.insert( expected.end(), response );\n\n    server.expected_output( server.notification, expected.begin(), expected.end(), server.connection );\n    server.connection.indication_confirmed();\n}\n\nBOOST_AUTO_TEST_SUITE( service_procedures )\n\n    /*\n     * TP/SPS/BV-01-C\n     */\n    BOOST_FIXTURE_TEST_CASE( set_cumulative_value__set_to_zero, discover_and_configure_all_descriptor< csc_server > )\n    {\n        // write to control point\n        l2cap_input({\n            0x12,\n            low( cs_control_point.value_attribute_handle ),\n            high( cs_control_point.value_attribute_handle ),\n            0x01,                    // resquest opcode (Set Cumulative Value)\n            0x00, 0x00, 0x00, 0x00   // 32 bit wheel value\n        });\n        expected_result({ 0x13 });\n\n        // check that callback was called\n        BOOST_CHECK_EQUAL( cumulative_wheel_revolutions(), 0u );\n\n        // trigger indication\n        confirm_cumulative_wheel_revolutions( *this );\n\n        check_cp_response( *this, {\n            0x10,  // response opcode\n            0x01,  // resquest opcode (Set Cumulative Value)\n            0x01   // success\n        });\n    }\n\n    /*\n     * TP/SPS/BV-02-C\n     */\n    BOOST_FIXTURE_TEST_CASE( set_cumulative_value__set_to_non_zero, discover_and_configure_all_descriptor< csc_server > )\n    {\n        // write to control point\n        l2cap_input({\n            0x12,\n            low( cs_control_point.value_attribute_handle ),\n            high( cs_control_point.value_attribute_handle ),\n            0x01,                    // resquest opcode (Set Cumulative Value)\n            0x01, 0x20, 0x30, 0x04   // 32 bit wheel value\n        });\n        expected_result({ 0x13 });\n\n        // check that callback was called\n        BOOST_CHECK_EQUAL( cumulative_wheel_revolutions(), 0x04302001u );\n\n        // trigger indication\n        confirm_cumulative_wheel_revolutions( *this );\n\n        check_cp_response( *this, {\n            0x10,  // response opcode\n            0x01,  // resquest opcode (Set Cumulative Value)\n            0x01   // success\n        });\n    }\n\n    BOOST_FIXTURE_TEST_CASE( set_cumulative_value__invalid_paramter__to_large, discover_and_configure_all_descriptor< csc_server > )\n    {\n        // write to control point\n        check_error_response(\n            {\n                0x12,\n                low( cs_control_point.value_attribute_handle ),\n                high( cs_control_point.value_attribute_handle ),\n                0x01,                    // resquest opcode (Set Cumulative Value)\n                0x01, 0x20, 0x30, 0x04, 0x05\n            },\n            0x12, cs_control_point.value_attribute_handle, 0x04 // invalid PDU\n        );\n    }\n\n\n    BOOST_FIXTURE_TEST_CASE( set_cumulative_value__invalid_paramter__to_small, discover_and_configure_all_descriptor< csc_server > )\n    {\n        // write to control point\n        check_error_response(\n            {\n                0x12,\n                low( cs_control_point.value_attribute_handle ),\n                high( cs_control_point.value_attribute_handle ),\n                0x01,                    // resquest opcode (Set Cumulative Value)\n                0x01, 0x20, 0x30\n            },\n            0x12, cs_control_point.value_attribute_handle, 0x04 // invalid PDU\n        );\n    }\n\n    /*\n     * TP/SPL/BV-01-C\n     */\n    BOOST_FIXTURE_TEST_CASE( request_supported_sensor_locations, discover_and_configure_all_descriptor< csc_server_with_multiple_sensor_locations > )\n    {\n        // write to control point\n        l2cap_input({\n            0x12,\n            low( cs_control_point.value_attribute_handle ),\n            high( cs_control_point.value_attribute_handle ),\n            0x04,     // resquest opcode (Request Supported Sensor Locations)\n        });\n        expected_result({ 0x13 });\n\n        check_cp_response( *this, {\n            0x10,  // response opcode\n            0x04,  // resquest opcode (Request Supported Sensor Locations)\n            0x01,  // success\n            0x01, 0x02, 0x03 // top_of_shoe, in_shoe, hip\n        });\n    }\n\n    BOOST_FIXTURE_TEST_CASE( request_supported_sensor_locations__no_multiple_sensor_locations, discover_and_configure_all_descriptor< csc_server > )\n    {\n        // write to control point\n        l2cap_input({\n            0x12,\n            low( cs_control_point.value_attribute_handle ),\n            high( cs_control_point.value_attribute_handle ),\n            0x04,     // resquest opcode (Request Supported Sensor Locations)\n        });\n        expected_result({ 0x13 });\n\n        check_cp_response( *this, {\n            0x10,  // response opcode\n            0x04,  // resquest opcode (Request Supported Sensor Locations)\n            0x02   // Op Code not supported\n        });\n    }\n\n    /*\n     * TP/SPU/BV-01-C\n     */\n    BOOST_FIXTURE_TEST_CASE( update_sensor_location__multiple_sensor_locations, discover_and_configure_all_descriptor< csc_server_with_multiple_sensor_locations > )\n    {\n        // write to control point\n        l2cap_input({\n            0x12,\n            low( cs_control_point.value_attribute_handle ),\n            high( cs_control_point.value_attribute_handle ),\n            0x03,     // resquest opcode (Update Sensor Locations)\n            0x03      // hip\n        });\n        expected_result({ 0x13 });\n\n        check_cp_response( *this, {\n            0x10,  // response opcode\n            0x03,  // resquest opcode (Update Sensor Locations)\n            0x01   // success\n        });\n\n        // check the position characteristic\n        l2cap_input({\n            0x0a,\n            low( sensor_location.value_attribute_handle ),\n            high( sensor_location.value_attribute_handle )\n        });\n        expected_result({ 0x0b, 0x03 });\n    }\n\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE( service_procedures__general_error_handling )\n\n    /*\n     * TP/SPE/BI-01-C\n     */\n    BOOST_FIXTURE_TEST_CASE( op_code_not_supported_1, discover_and_configure_all_descriptor< csc_server > )\n    {\n        // write to control point\n        l2cap_input({\n            0x12,\n            low( cs_control_point.value_attribute_handle ),\n            high( cs_control_point.value_attribute_handle ),\n            0x00     // resquest opcode (invalid)\n        });\n        expected_result({ 0x13 });\n\n        check_cp_response( *this, {\n            0x10,  // response opcode\n            0x00,  // resquest opcode (invalid)\n            0x02   // Op Code not supported\n        });\n    }\n\n    BOOST_FIXTURE_TEST_CASE( op_code_not_supported_2, discover_and_configure_all_descriptor< csc_server > )\n    {\n        // write to control point\n        l2cap_input({\n            0x12,\n            low( cs_control_point.value_attribute_handle ),\n            high( cs_control_point.value_attribute_handle ),\n            0x42     // resquest opcode (invalid)\n        });\n        expected_result({ 0x13 });\n\n        check_cp_response( *this, {\n            0x10,  // response opcode\n            0x42,  // resquest opcode (invalid)\n            0x02   // Op Code not supported\n        });\n    }\n\n    /*\n     * TP/SPE/BI-02-C\n     */\n    BOOST_FIXTURE_TEST_CASE( invalid_parameter, discover_and_configure_all_descriptor< csc_server_with_multiple_sensor_locations > )\n    {\n        // write to control point\n        l2cap_input({\n            0x12,\n            low( cs_control_point.value_attribute_handle ),\n            high( cs_control_point.value_attribute_handle ),\n            0x03,     // resquest opcode (UpdateSensorLocation)\n            0x42      // sensor location from the RFU range\n        });\n        expected_result({ 0x13 });\n\n        check_cp_response( *this, {\n            0x10,  // response opcode\n            0x03,  // resquest opcode (UpdateSensorLocation)\n            0x03   // Invalid Parameter\n        });\n    }\n\n    /*\n     * TP/SPE/BI-03-C\n     */\n    BOOST_FIXTURE_TEST_CASE( client_characteristic_configuration_descriptor_improperly_configured, discover_all_descriptors< csc_server > )\n    {\n        // valid command to set the cumulative wheel\n        check_error_response({\n            0x12,\n            low( cs_control_point.value_attribute_handle ),\n            high( cs_control_point.value_attribute_handle ),\n            0x01,                    // resquest opcode (Set Cumulative Value)\n            0x00, 0x00, 0x00, 0x00   // 32 bit wheel value\n        },\n        // according to the TS/spec, 0x81 should be returned. But there is already an error code defined in Supplement to the Bluetooth Core Specification\n        0x12, cs_control_point.value_attribute_handle, 0xfd );\n    }\n\n    /*\n     * TP/SPE/BI-04-C\n     *\n     * This one is hard to test, because it requires the implementation to be asynchronous somewhere.\n     * Currently the only asynchronous procedure is\n     */\n    BOOST_FIXTURE_TEST_CASE( procedure_already_in_progress, discover_and_configure_all_descriptor< csc_server > )\n    {\n        // write to control point\n        l2cap_input({\n            0x12,\n            low( cs_control_point.value_attribute_handle ),\n            high( cs_control_point.value_attribute_handle ),\n            0x01,                    // resquest opcode (Set Cumulative Value)\n            0x01, 0x20, 0x30, 0x04   // 32 bit wheel value\n        });\n        expected_result({ 0x13 });\n\n        // write to control point\n        check_error_response({\n            0x12,\n            low( cs_control_point.value_attribute_handle ),\n            high( cs_control_point.value_attribute_handle ),\n            0x01,                    // resquest opcode (Set Cumulative Value)\n            0x01, 0x20, 0x30, 0x04   // 32 bit wheel value\n        },\n        // according to the TS/spec, 0x80 should be returned. But there is already an error code defined in Supplement to the Bluetooth Core Specification\n        0x12, cs_control_point.value_attribute_handle, 0xfe );\n    }\n\n    /*\n     * TP/SPE/BI-05-C [SC Control Point Procedure Timeout]\n     *\n     * Not implemented\n     */\n\n    BOOST_FIXTURE_TEST_CASE( multiple_control_point_procedures, discover_and_configure_all_descriptor< csc_server_with_multiple_sensor_locations > )\n    {\n        l2cap_input({\n            0x12,\n            low( cs_control_point.value_attribute_handle ),\n            high( cs_control_point.value_attribute_handle ),\n            0x01,                    // resquest opcode (Set Cumulative Value)\n            0x01, 0x20, 0x30, 0x04   // 32 bit wheel value\n        });\n        expected_result({ 0x13 });\n\n        // check that callback was called\n        BOOST_CHECK_EQUAL( cumulative_wheel_revolutions(), 0x04302001u );\n\n        // trigger indication\n        confirm_cumulative_wheel_revolutions( *this );\n\n        check_cp_response( *this, {\n            0x10,  // response opcode\n            0x01,  // resquest opcode (UpdateSensorLocation)\n            0x01   // success\n        });\n\n        // set sensor location\n        l2cap_input({\n            0x12,\n            low( cs_control_point.value_attribute_handle ),\n            high( cs_control_point.value_attribute_handle ),\n            0x03,     // resquest opcode (UpdateSensorLocation)\n            0x02      // sensor location (in shoe)\n        });\n        expected_result({ 0x13 });\n\n        check_cp_response( *this, {\n            0x10,  // response opcode\n            0x03,  // resquest opcode (UpdateSensorLocation)\n            0x01   // success\n        });\n    }\n\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE( sensor_location )\n\n    BOOST_FIXTURE_TEST_CASE( sensor_position__hip, discover_and_configure_all_descriptor< csc_server_with_sensorposition< bluetoe::sensor_location::hip > > )\n    {\n        l2cap_input({\n            0x0a,\n            low( sensor_location.value_attribute_handle ),\n            high( sensor_location.value_attribute_handle )\n        });\n        expected_result({ 0x0b, 0x03 });\n    }\n\n    BOOST_FIXTURE_TEST_CASE( sensor_position__rear_dropout, discover_and_configure_all_descriptor< csc_server_with_sensorposition< bluetoe::sensor_location::rear_dropout > > )\n    {\n        l2cap_input({\n            0x0a,\n            low( sensor_location.value_attribute_handle ),\n            high( sensor_location.value_attribute_handle )\n        });\n        expected_result({ 0x0b, 0x0a });\n    }\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "tests/services/test_gatt.cpp",
    "content": "#include \"test_gatt.hpp\"\n#include <hexdump.hpp>\n#include <iomanip>\n\nnamespace test {\n    discovered_service::discovered_service( std::uint16_t start, std::uint16_t end )\n        : starting_handle( start )\n        , ending_handle( end )\n    {\n    }\n\n    discovered_service::discovered_service()\n        : starting_handle( invalid_handle )\n        , ending_handle( invalid_handle )\n    {\n    }\n\n    bool discovered_service::operator==( const discovered_service& rhs ) const\n    {\n        return starting_handle == rhs.starting_handle\n            && ending_handle == rhs.ending_handle;\n    }\n\n    std::ostream& operator<<( std::ostream& out, const discovered_service& service )\n    {\n        return out << std::hex << \"{ 0x\" << service.starting_handle << \", 0x\" << service.ending_handle << \" }\";\n    }\n\n    discovered_characteristic::discovered_characteristic( std::uint16_t decl, std::uint16_t value, std::uint8_t p, const dynamic_uuid& u )\n        : declaration_handle( decl )\n        , end_handle( invalid_handle )\n        , value_handle( value )\n        , properties( p )\n        , uuid( u )\n    {\n\n    }\n\n    discovered_characteristic::discovered_characteristic()\n        : declaration_handle( invalid_handle )\n        , end_handle( invalid_handle )\n        , value_handle( invalid_handle )\n        , uuid()\n    {\n\n    }\n\n    bool discovered_characteristic::operator==( const discovered_characteristic& rhs ) const\n    {\n        return declaration_handle == rhs.declaration_handle\n            && end_handle == rhs.end_handle\n            && value_handle == rhs.value_handle\n            && properties == rhs.properties\n            && uuid == rhs.uuid;\n    }\n\n    std::ostream& operator<<( std::ostream& out, const discovered_characteristic& characteristic )\n    {\n        return out\n            << std::hex << \"{ 0x\" << characteristic.declaration_handle << \":0x\" << characteristic.end_handle\n            << \", 0x\" << characteristic.properties\n            << \", 0x\" << characteristic.value_handle\n            << \", \" << characteristic.uuid << \" }\";\n    }\n\n    discovered_characteristic_descriptor::discovered_characteristic_descriptor( std::uint16_t h, std::uint16_t u )\n        : handle( h )\n        , uuid( u )\n    {\n    }\n\n    discovered_characteristic_descriptor::discovered_characteristic_descriptor()\n        : handle( invalid_handle )\n        , uuid( invalid_handle )\n    {\n    }\n\n    bool discovered_characteristic_descriptor::operator==( const discovered_characteristic_descriptor& rhs ) const\n    {\n        return handle == rhs.handle\n            && uuid == rhs.uuid;\n    }\n\n    std::ostream& operator<<( std::ostream& out, const discovered_characteristic_descriptor& desc )\n    {\n        return out << std::hex << \"{ 0x\" << desc.handle << \", 0x\" << desc.uuid << \" }\";\n    }\n\n}\n"
  },
  {
    "path": "tests/services/test_gatt.hpp",
    "content": "#ifndef BLUETOE_TESTS_SERVICE_TEST_DISCOVERY_HPP\n#define BLUETOE_TESTS_SERVICE_TEST_DISCOVERY_HPP\n\n#include <boost/test/unit_test.hpp>\n\n#include \"test_servers.hpp\"\n#include \"hexdump.hpp\"\n#include \"test_uuid.hpp\"\n\n#include <ostream>\n#include <vector>\n\nnamespace test {\n\n    static constexpr std::uint16_t invalid_handle = 0;\n\n    struct discovered_service\n    {\n        std::uint16_t starting_handle;\n        std::uint16_t ending_handle;\n\n        discovered_service( std::uint16_t start, std::uint16_t end );\n        discovered_service();\n\n        bool operator==( const discovered_service& rhs ) const;\n    };\n\n    std::ostream& operator<<( std::ostream& out, const discovered_service& );\n\n    struct discovered_characteristic\n    {\n        std::uint16_t declaration_handle;\n        std::uint16_t end_handle;\n        std::uint16_t value_handle;\n        std::uint8_t  properties;\n        dynamic_uuid  uuid;\n\n        discovered_characteristic( std::uint16_t decl, std::uint16_t value, std::uint8_t  properties, const dynamic_uuid& uuid );\n        discovered_characteristic();\n\n        bool operator==( const discovered_characteristic& rhs ) const;\n    };\n\n    std::ostream& operator<<( std::ostream& out, const discovered_characteristic& );\n\n    struct discovered_characteristic_descriptor\n    {\n        std::uint16_t   handle;\n        std::uint16_t   uuid;\n\n        discovered_characteristic_descriptor( std::uint16_t handle, std::uint16_t uuid );\n        discovered_characteristic_descriptor();\n\n        bool operator==( const discovered_characteristic_descriptor& rhs ) const;\n    };\n\n    std::ostream& operator<<( std::ostream& out, const discovered_characteristic_descriptor& );\n\n    template < typename Server, std::size_t MTU = 23 >\n    struct gatt_procedures : request_with_reponse< Server, MTU >\n    {\n        static std::uint8_t low( std::uint16_t b )\n        {\n            return b & 0xff;\n        }\n\n        static std::uint8_t high( std::uint16_t b )\n        {\n            return b >> 8;\n        }\n\n        void add_handle( std::vector< std::uint8_t >& buffer, std::uint16_t handle )\n        {\n            buffer.push_back( low( handle ) );\n            buffer.push_back( high( handle ) );\n        }\n\n        void add_handle( std::vector< std::uint8_t >& buffer, std::uint16_t h1, std::uint16_t h2 )\n        {\n            add_handle( buffer, h1 );\n            add_handle( buffer, h2 );\n        }\n\n        void add_uuid( std::vector< std::uint8_t >& buffer, std::uint16_t uuid )\n        {\n            return add_handle( buffer, uuid );\n        }\n\n        std::uint16_t handle_at( std::size_t pos )\n        {\n            return this->response[ pos ] | ( this->response[ pos + 1 ] <<  8);\n        }\n\n        template < class UUID >\n        discovered_service discover_primary_service_by_uuid()\n        {\n            std::vector< std::uint8_t > request = { 0x06, 0x01, 0x00, 0xff, 0xff, 0x00, 0x28 };\n            request.insert( request.end(), std::begin( UUID::bytes ), std::end( UUID::bytes ) );\n\n            this->l2cap_input( request, this->connection );\n\n            BOOST_REQUIRE_GT( this->response_size, 0u );\n\n            if ( this->response[ 0 ] == 0x07 )\n            {\n                BOOST_REQUIRE_EQUAL( this->response_size, 5u );\n                return discovered_service(\n                    this->response[ 1 ] | ( this->response[ 2 ] << 8 ),\n                    this->response[ 3 ] | ( this->response[ 4 ] << 8 ) );\n            }\n\n            return discovered_service();\n        }\n\n        std::vector< discovered_characteristic > discover_all_characteristics_of_a_service( const discovered_service& service )\n        {\n            std::vector< discovered_characteristic > result;\n\n            std::uint8_t last_response_code = 0x09;\n\n            for ( std::uint16_t start_handle = service.starting_handle; last_response_code == 0x09;  )\n            {\n                std::vector< std::uint8_t > request = { 0x08 };\n                add_handle( request, start_handle, service.ending_handle );\n                add_uuid( request, 0x2803 );\n\n                this->l2cap_input( request, this->connection );\n                BOOST_REQUIRE_GT( this->response_size, 0u );\n\n                last_response_code = this->response[ 0 ];\n                if ( last_response_code == 0x09 )\n                {\n                    BOOST_REQUIRE_GT( this->response_size, 1u );\n                    const std::size_t length = this->response[ 1 ];\n\n                    BOOST_REQUIRE( length == 2 + 3 + 2 || length == 2 + 3 + 16 );\n                    BOOST_REQUIRE_EQUAL( ( this->response_size - 2 ) % length, 0u );\n                    BOOST_REQUIRE_GT( ( this->response_size - 2 ) / length, 0u );\n\n                    for ( std::size_t ptr = 2; ptr != this->response_size; ptr += length )\n                    {\n                        start_handle = handle_at( ptr + 3 ) + 1;\n                        dynamic_uuid uuid( &this->response[ ptr + 5 ], length - 5 );\n\n                        result.push_back(\n                            discovered_characteristic( handle_at( ptr ), handle_at( ptr + 3 ), this->response[ ptr + 2 ], uuid ) );\n                    }\n                }\n            }\n\n            for ( std::vector< discovered_characteristic >::iterator uuid = result.begin(); uuid != result.end(); ++uuid )\n            {\n                const auto next = uuid +1;\n                uuid->end_handle = next != result.end()\n                    ? next->declaration_handle - 1\n                    : service.ending_handle;\n            }\n\n            return result;\n        }\n\n        template < class UUID >\n        discovered_characteristic discover_characteristic_by_uuid( const discovered_service& service )\n        {\n            const std::vector< discovered_characteristic > all = discover_all_characteristics_of_a_service( service );\n            const dynamic_uuid service_uuid( static_cast< const UUID* >( nullptr ) );\n\n            auto result = std::find_if( all.begin(), all.end(),\n                [ &service_uuid ]( const discovered_characteristic& c ){ return c.uuid == service_uuid ; } );\n\n            return result != all.end()\n                ? *result\n                : discovered_characteristic();\n        }\n\n        std::vector< discovered_characteristic_descriptor > discover_all_characteristic_descriptors( const discovered_characteristic& characteristic )\n        {\n            std::vector< discovered_characteristic_descriptor > result;\n\n            std::uint8_t last_response_code = 0x05;\n\n            for ( std::uint16_t start_handle = characteristic.value_handle +1; last_response_code == 0x05;  )\n            {\n                std::vector< std::uint8_t > request = { 0x04 };\n                add_handle( request, start_handle, characteristic.end_handle );\n\n                this->l2cap_input( request, this->connection );\n                BOOST_REQUIRE_GT( this->response_size, 0u );\n\n                last_response_code = this->response[ 0 ];\n                if ( last_response_code == 0x05 )\n                {\n                    BOOST_REQUIRE_GT( this->response_size, 1u );\n                    const std::size_t format = this->response[ 1 ];\n\n                    // 16 bit uuid\n                    BOOST_REQUIRE( format == 0x01 );\n                    static constexpr std::size_t length = 4;\n                    BOOST_REQUIRE_EQUAL( ( this->response_size - 2 ) % length, 0u );\n                    BOOST_REQUIRE_GT( ( this->response_size - 2 ) / length, 0u );\n\n                    for ( std::size_t ptr = 2; ptr != this->response_size; ptr += length )\n                    {\n                        start_handle = handle_at( ptr ) + 1;\n\n                        result.push_back(\n                            discovered_characteristic_descriptor( handle_at( ptr ), handle_at( ptr + 2 ) ) );\n                    }\n                }\n            }\n\n            return result;\n        }\n\n        discovered_characteristic_descriptor discover_cccd( const discovered_characteristic& characteristic )\n        {\n            const std::vector< discovered_characteristic_descriptor > descriptors = discover_all_characteristic_descriptors( characteristic );\n\n            const auto result = std::find_if( descriptors.begin(), descriptors.end(),\n                []( const discovered_characteristic_descriptor& d ){ return d.uuid == 0x2902; } );\n\n            return result != descriptors.end()\n                ? *result\n                : discovered_characteristic_descriptor();\n        }\n    };\n}\n\n#endif\n"
  },
  {
    "path": "tests/test_attribute_access.hpp",
    "content": "#ifndef BLUETOE_TESTS_TEST_ATTRIBUTE_ACCESS_HPP\n#define BLUETOE_TESTS_TEST_ATTRIBUTE_ACCESS_HPP\n\n#include <bluetoe/attribute.hpp>\n#include <bluetoe/server.hpp>\n\ntemplate < typename Char, typename Service = bluetoe::service< bluetoe::service_uuid16< 0x4711 >, Char >, typename Server = bluetoe::server< Service > >\nclass access_attributes : public Char, public bluetoe::details::client_characteristic_configurations< Char::number_of_client_configs >\n{\npublic:\n    using cccd_indices = std::tuple<>;\n\n    std::pair< bool, bluetoe::details::attribute > find_attribute_by_type( std::uint16_t type )\n    {\n        for ( int index = 0; index != this->number_of_attributes; ++index )\n        {\n            const bluetoe::details::attribute value_attribute = attribute_at_impl( index );\n\n            if ( value_attribute.uuid == type )\n            {\n                return std::make_pair( true, value_attribute );\n            }\n        }\n\n        return std::pair< bool, bluetoe::details::attribute >( false, bluetoe::details::attribute{ 0, nullptr } );\n    }\n\n    bluetoe::details::attribute attribute_by_type( std::uint16_t type )\n    {\n        for ( int index = 0; index != this->number_of_attributes; ++index )\n        {\n            const bluetoe::details::attribute value_attribute = attribute_at_impl( index );\n\n            if ( value_attribute.uuid == type )\n            {\n                return value_attribute;\n            }\n        }\n\n        BOOST_REQUIRE( !\"Type not found\" );\n\n        return bluetoe::details::attribute{ 0, 0 };\n    }\n\n    void compare_characteristic_at( const std::initializer_list< std::uint8_t >& input, std::size_t index )\n    {\n        BOOST_REQUIRE(\n            bluetoe::details::attribute_access_result::success\n                == read_characteristic_impl( input, attribute_at_impl( index ) ) );\n    }\n\n    void compare_characteristic( const std::initializer_list< std::uint8_t >& input, std::uint16_t type )\n    {\n        BOOST_REQUIRE(\n            bluetoe::details::attribute_access_result::success\n                == read_characteristic_impl( input, attribute_by_type( type ) ) );\n    }\n\n    bluetoe::details::attribute_access_result read_attribute_at( const std::initializer_list< std::uint8_t >& input,\n        std::size_t index, std::size_t offset, std::size_t buffer_size )\n    {\n        return read_characteristic_impl( input, attribute_at_impl( index ), offset, buffer_size );\n    }\n\n    bluetoe::details::attribute_access_result write_attribute_at( const std::uint8_t* begin, const std::uint8_t* end, std::size_t index = 1, std::size_t offset = 0 )\n    {\n        auto write = bluetoe::details::attribute_access_arguments::write(\n            begin, end, offset,\n            bluetoe::details::client_characteristic_configuration(),\n            security_,\n            nullptr );\n\n        return attribute_at_impl( index ).access( write, index );\n    }\n\n    bluetoe::details::attribute_access_result write_attribute_at( const std::initializer_list< std::uint8_t >& input, std::size_t index = 1, std::size_t offset = 0 )\n    {\n        return write_attribute_at( input.begin(), input.end(), index, offset );\n    }\n\n    access_attributes()\n        : security_()\n    {\n    }\n\n    explicit access_attributes( bluetoe::connection_security_attributes security )\n        : security_( security )\n    {\n    }\n\nprivate:\n    bluetoe::details::attribute attribute_at_impl( std::size_t idx )\n    {\n        return this->template attribute_at< cccd_indices, 0, Service, Server >( idx );\n    }\n\n    bluetoe::details::attribute_access_result read_characteristic_impl(\n        const std::initializer_list< std::uint8_t >& input,\n        const bluetoe::details::attribute& value_attribute,\n        std::size_t offset = 0,\n        std::size_t buffer_size = 100 )\n    {\n        std::uint8_t buffer[ 1000 ];\n        auto read = bluetoe::details::attribute_access_arguments::read(\n            &buffer[ 0 ], &buffer[ buffer_size ], offset,\n            this->client_configurations(),\n            security_,\n            nullptr );\n\n        auto result = value_attribute.access( read, 0 );\n\n        if ( result == bluetoe::details::attribute_access_result::success )\n            BOOST_REQUIRE_EQUAL_COLLECTIONS( input.begin(), input.end(), &read.buffer[ 0 ], &read.buffer[ read.buffer_size ] );\n\n        return result;\n    }\n\n    using suuid = bluetoe::service_uuid16< 0x4711 >;\n    bluetoe::connection_security_attributes security_;\n};\n\n\n#endif\n"
  },
  {
    "path": "tests/test_characteristics.hpp",
    "content": "#ifndef BLUETOE_TESTS_CHARACTERISTICS_HPP\n#define BLUETOE_TESTS_CHARACTERISTICS_HPP\n\n#include <bluetoe/characteristic_value.hpp>\n\nnamespace {\n    std::uint32_t       simple_value       = 0xaabbccdd;\n    const std::uint32_t simple_const_value = 0xaabbccdd;\n\n    typedef bluetoe::characteristic<\n        bluetoe::characteristic_uuid< 0xD0B10674, 0x6DDD, 0x4B59, 0x89CA, 0xA009B78C956B >,\n        bluetoe::bind_characteristic_value< std::uint32_t, &simple_value >\n    > simple_char;\n\n   typedef bluetoe::characteristic<\n        bluetoe::characteristic_uuid16< 0xD0B1 >,\n        bluetoe::bind_characteristic_value< std::uint32_t, &simple_value >\n    > short_uuid_char;\n\n    typedef bluetoe::characteristic<\n        bluetoe::characteristic_uuid< 0xD0B10674, 0x6DDD, 0x4B59, 0x89CA, 0xA009B78C956B >,\n        bluetoe::bind_characteristic_value< const std::uint32_t, &simple_const_value >\n    > simple_const_char;\n\n    template < typename Char >\n    struct read_characteristic_properties : Char\n    {\n        read_characteristic_properties()\n        {\n            using suuid = bluetoe::service_uuid16< 0x4711 >;\n            using srv   = bluetoe::server<>;\n\n            const bluetoe::details::attribute value_attribute = this->template attribute_at< std::tuple<>, 0, bluetoe::service< suuid >, srv >( 0 );\n            std::uint8_t buffer[ 100 ];\n            auto read = bluetoe::details::attribute_access_arguments::read( buffer, 0 );\n\n            BOOST_REQUIRE( bluetoe::details::attribute_access_result::success == value_attribute.access( read, 1 ) );\n            properties = buffer[ 0 ];\n        }\n\n        std::uint8_t properties;\n    };\n\n}\n\n#endif // include guard\n"
  },
  {
    "path": "tests/test_tools/CMakeLists.txt",
    "content": "find_package( Boost REQUIRED )\n\nenable_language(C)\n\nadd_library(test_tools STATIC\n        aes.c\n        address_io.cpp\n        attribute_io.cpp\n        test_uuid.cpp\n        test_servers.cpp\n        hexdump.cpp\n        test_radio.cpp\n        buffer_io.cpp\n        pairing_status_io.cpp\n        uECC.c)\n\nadd_library(test::tools ALIAS test_tools)\n\ntarget_include_directories(test_tools PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})\ntarget_include_directories(test_tools PRIVATE ${Boost_INCLUDE_DIR})\ntarget_link_libraries(test_tools PRIVATE bluetoe::link_layer bluetoe::utility bluetoe::iface)\ntarget_compile_features(test_tools PRIVATE cxx_std_11)\ntarget_compile_definitions(test_tools PRIVATE \"\")\n\nset_property(TARGET test_tools PROPERTY C_STANDARD 99)\nset_source_files_properties(uECC.c PROPERTIES COMPILE_FLAGS -Wno-unused-variable)\nset_source_files_properties(uECC.c PROPERTIES COMPILE_DEFINITIONS uECC_CURVE=uECC_secp256r1)\n"
  },
  {
    "path": "tests/test_tools/address_io.cpp",
    "content": "#include <bluetoe/address.hpp>\n#include <ostream>\n#include <iomanip>\n#include <boost/io/ios_state.hpp>\n\nnamespace bluetoe {\nnamespace link_layer {\n\n    std::ostream& address::print( std::ostream& out ) const\n    {\n        boost::io::ios_all_saver save_flags( out );\n\n        auto begin = std::begin( value_ );\n        auto end   = std::end( value_ );\n\n        out << std::hex << std::setfill( '0' ) << std::setw( 2 ) << static_cast< unsigned >( *begin );\n        ++begin;\n\n        for ( ; begin != end; ++begin )\n        {\n            out << ':' << std::setw( 2 ) << static_cast< unsigned >( *begin );\n        }\n\n        return out;\n    }\n\n    std::ostream& operator<<( std::ostream& out, const address& a )\n    {\n        return a.print( out );\n    }\n\n    std::ostream& operator<<( std::ostream& out, const device_address& a )\n    {\n        return out << static_cast< const address& >( a ) << ( a.is_public() ? \" (public)\" : \" (random)\");\n    }\n\n}\n}\n"
  },
  {
    "path": "tests/test_tools/aes.c",
    "content": "/*\n\nThis is an implementation of the AES algorithm, specifically ECB, CTR and CBC mode.\nBlock size can be chosen in aes.h - available choices are AES128, AES192, AES256.\n\nThe implementation is verified against the test vectors in:\n  National Institute of Standards and Technology Special Publication 800-38A 2001 ED\n\nECB-AES128\n----------\n\n  plain-text:\n    6bc1bee22e409f96e93d7e117393172a\n    ae2d8a571e03ac9c9eb76fac45af8e51\n    30c81c46a35ce411e5fbc1191a0a52ef\n    f69f2445df4f9b17ad2b417be66c3710\n\n  key:\n    2b7e151628aed2a6abf7158809cf4f3c\n\n  resulting cipher\n    3ad77bb40d7a3660a89ecaf32466ef97\n    f5d3d58503b9699de785895a96fdbaaf\n    43b1cd7f598ece23881b00e3ed030688\n    7b0c785e27e8ad3f8223207104725dd4\n\n\nNOTE:   String length must be evenly divisible by 16byte (str_len % 16 == 0)\n        You should pad the end of the string with zeros if this is not the case.\n        For AES192/256 the key size is proportionally larger.\n\n*/\n\n\n/*****************************************************************************/\n/* Includes:                                                                 */\n/*****************************************************************************/\n#include <stdint.h>\n#include <string.h> // CBC mode, for memset\n#include \"aes.h\"\n\n/*****************************************************************************/\n/* Defines:                                                                  */\n/*****************************************************************************/\n// The number of columns comprising a state in AES. This is a constant in AES. Value=4\n#define Nb 4\n\n#if defined(AES256) && (AES256 == 1)\n    #define Nk 8\n    #define Nr 14\n#elif defined(AES192) && (AES192 == 1)\n    #define Nk 6\n    #define Nr 12\n#else\n    #define Nk 4        // The number of 32 bit words in a key.\n    #define Nr 10       // The number of rounds in AES Cipher.\n#endif\n\n// jcallan@github points out that declaring Multiply as a function\n// reduces code size considerably with the Keil ARM compiler.\n// See this link for more information: https://github.com/kokke/tiny-AES-C/pull/3\n#ifndef MULTIPLY_AS_A_FUNCTION\n  #define MULTIPLY_AS_A_FUNCTION 0\n#endif\n\n\n\n\n/*****************************************************************************/\n/* Private variables:                                                        */\n/*****************************************************************************/\n// state - array holding the intermediate results during decryption.\ntypedef uint8_t state_t[4][4];\n\n\n\n// The lookup-tables are marked const so they can be placed in read-only storage instead of RAM\n// The numbers below can be computed dynamically trading ROM for RAM -\n// This can be useful in (embedded) bootloader applications, where ROM is often limited.\nstatic const uint8_t sbox[256] = {\n  //0     1    2      3     4    5     6     7      8    9     A      B    C     D     E     F\n  0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,\n  0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,\n  0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,\n  0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,\n  0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,\n  0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,\n  0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,\n  0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,\n  0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,\n  0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,\n  0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,\n  0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,\n  0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,\n  0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,\n  0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,\n  0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 };\n\nstatic const uint8_t rsbox[256] = {\n  0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb,\n  0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb,\n  0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,\n  0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25,\n  0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92,\n  0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,\n  0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06,\n  0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b,\n  0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,\n  0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e,\n  0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b,\n  0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,\n  0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f,\n  0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef,\n  0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,\n  0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d };\n\n// The round constant word array, Rcon[i], contains the values given by\n// x to the power (i-1) being powers of x (x is denoted as {02}) in the field GF(2^8)\nstatic const uint8_t Rcon[11] = {\n  0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36 };\n\n/*\n * Jordan Goulder points out in PR #12 (https://github.com/kokke/tiny-AES-C/pull/12),\n * that you can remove most of the elements in the Rcon array, because they are unused.\n *\n * From Wikipedia's article on the Rijndael key schedule @ https://en.wikipedia.org/wiki/Rijndael_key_schedule#Rcon\n *\n * \"Only the first some of these constants are actually used – up to rcon[10] for AES-128 (as 11 round keys are needed),\n *  up to rcon[8] for AES-192, up to rcon[7] for AES-256. rcon[0] is not used in AES algorithm.\"\n */\n\n\n/*****************************************************************************/\n/* Private functions:                                                        */\n/*****************************************************************************/\n/*\nstatic uint8_t getSBoxValue(uint8_t num)\n{\n  return sbox[num];\n}\n*/\n#define getSBoxValue(num) (sbox[(num)])\n/*\nstatic uint8_t getSBoxInvert(uint8_t num)\n{\n  return rsbox[num];\n}\n*/\n#define getSBoxInvert(num) (rsbox[(num)])\n\n// This function produces Nb(Nr+1) round keys. The round keys are used in each round to decrypt the states.\nstatic void KeyExpansion(uint8_t* RoundKey, const uint8_t* Key)\n{\n  unsigned i, j, k;\n  uint8_t tempa[4]; // Used for the column/row operations\n\n  // The first round key is the key itself.\n  for (i = 0; i < Nk; ++i)\n  {\n    RoundKey[(i * 4) + 0] = Key[(i * 4) + 0];\n    RoundKey[(i * 4) + 1] = Key[(i * 4) + 1];\n    RoundKey[(i * 4) + 2] = Key[(i * 4) + 2];\n    RoundKey[(i * 4) + 3] = Key[(i * 4) + 3];\n  }\n\n  // All other round keys are found from the previous round keys.\n  for (i = Nk; i < Nb * (Nr + 1); ++i)\n  {\n    {\n      k = (i - 1) * 4;\n      tempa[0]=RoundKey[k + 0];\n      tempa[1]=RoundKey[k + 1];\n      tempa[2]=RoundKey[k + 2];\n      tempa[3]=RoundKey[k + 3];\n\n    }\n\n    if (i % Nk == 0)\n    {\n      // This function shifts the 4 bytes in a word to the left once.\n      // [a0,a1,a2,a3] becomes [a1,a2,a3,a0]\n\n      // Function RotWord()\n      {\n        k = tempa[0];\n        tempa[0] = tempa[1];\n        tempa[1] = tempa[2];\n        tempa[2] = tempa[3];\n        tempa[3] = k;\n      }\n\n      // SubWord() is a function that takes a four-byte input word and\n      // applies the S-box to each of the four bytes to produce an output word.\n\n      // Function Subword()\n      {\n        tempa[0] = getSBoxValue(tempa[0]);\n        tempa[1] = getSBoxValue(tempa[1]);\n        tempa[2] = getSBoxValue(tempa[2]);\n        tempa[3] = getSBoxValue(tempa[3]);\n      }\n\n      tempa[0] = tempa[0] ^ Rcon[i/Nk];\n    }\n#if defined(AES256) && (AES256 == 1)\n    if (i % Nk == 4)\n    {\n      // Function Subword()\n      {\n        tempa[0] = getSBoxValue(tempa[0]);\n        tempa[1] = getSBoxValue(tempa[1]);\n        tempa[2] = getSBoxValue(tempa[2]);\n        tempa[3] = getSBoxValue(tempa[3]);\n      }\n    }\n#endif\n    j = i * 4; k=(i - Nk) * 4;\n    RoundKey[j + 0] = RoundKey[k + 0] ^ tempa[0];\n    RoundKey[j + 1] = RoundKey[k + 1] ^ tempa[1];\n    RoundKey[j + 2] = RoundKey[k + 2] ^ tempa[2];\n    RoundKey[j + 3] = RoundKey[k + 3] ^ tempa[3];\n  }\n}\n\nvoid AES_init_ctx(struct AES_ctx* ctx, const uint8_t* key)\n{\n  KeyExpansion(ctx->RoundKey, key);\n}\n#if (defined(CBC) && (CBC == 1)) || (defined(CTR) && (CTR == 1))\nvoid AES_init_ctx_iv(struct AES_ctx* ctx, const uint8_t* key, const uint8_t* iv)\n{\n  KeyExpansion(ctx->RoundKey, key);\n  memcpy (ctx->Iv, iv, AES_BLOCKLEN);\n}\nvoid AES_ctx_set_iv(struct AES_ctx* ctx, const uint8_t* iv)\n{\n  memcpy (ctx->Iv, iv, AES_BLOCKLEN);\n}\n#endif\n\n// This function adds the round key to state.\n// The round key is added to the state by an XOR function.\nstatic void AddRoundKey(uint8_t round,state_t* state,uint8_t* RoundKey)\n{\n  uint8_t i,j;\n  for (i = 0; i < 4; ++i)\n  {\n    for (j = 0; j < 4; ++j)\n    {\n      (*state)[i][j] ^= RoundKey[(round * Nb * 4) + (i * Nb) + j];\n    }\n  }\n}\n\n// The SubBytes Function Substitutes the values in the\n// state matrix with values in an S-box.\nstatic void SubBytes(state_t* state)\n{\n  uint8_t i, j;\n  for (i = 0; i < 4; ++i)\n  {\n    for (j = 0; j < 4; ++j)\n    {\n      (*state)[j][i] = getSBoxValue((*state)[j][i]);\n    }\n  }\n}\n\n// The ShiftRows() function shifts the rows in the state to the left.\n// Each row is shifted with different offset.\n// Offset = Row number. So the first row is not shifted.\nstatic void ShiftRows(state_t* state)\n{\n  uint8_t temp;\n\n  // Rotate first row 1 columns to left\n  temp           = (*state)[0][1];\n  (*state)[0][1] = (*state)[1][1];\n  (*state)[1][1] = (*state)[2][1];\n  (*state)[2][1] = (*state)[3][1];\n  (*state)[3][1] = temp;\n\n  // Rotate second row 2 columns to left\n  temp           = (*state)[0][2];\n  (*state)[0][2] = (*state)[2][2];\n  (*state)[2][2] = temp;\n\n  temp           = (*state)[1][2];\n  (*state)[1][2] = (*state)[3][2];\n  (*state)[3][2] = temp;\n\n  // Rotate third row 3 columns to left\n  temp           = (*state)[0][3];\n  (*state)[0][3] = (*state)[3][3];\n  (*state)[3][3] = (*state)[2][3];\n  (*state)[2][3] = (*state)[1][3];\n  (*state)[1][3] = temp;\n}\n\nstatic uint8_t xtime(uint8_t x)\n{\n  return ((x<<1) ^ (((x>>7) & 1) * 0x1b));\n}\n\n// MixColumns function mixes the columns of the state matrix\nstatic void MixColumns(state_t* state)\n{\n  uint8_t i;\n  uint8_t Tmp, Tm, t;\n  for (i = 0; i < 4; ++i)\n  {\n    t   = (*state)[i][0];\n    Tmp = (*state)[i][0] ^ (*state)[i][1] ^ (*state)[i][2] ^ (*state)[i][3] ;\n    Tm  = (*state)[i][0] ^ (*state)[i][1] ; Tm = xtime(Tm);  (*state)[i][0] ^= Tm ^ Tmp ;\n    Tm  = (*state)[i][1] ^ (*state)[i][2] ; Tm = xtime(Tm);  (*state)[i][1] ^= Tm ^ Tmp ;\n    Tm  = (*state)[i][2] ^ (*state)[i][3] ; Tm = xtime(Tm);  (*state)[i][2] ^= Tm ^ Tmp ;\n    Tm  = (*state)[i][3] ^ t ;              Tm = xtime(Tm);  (*state)[i][3] ^= Tm ^ Tmp ;\n  }\n}\n\n// Multiply is used to multiply numbers in the field GF(2^8)\n#if MULTIPLY_AS_A_FUNCTION\nstatic uint8_t Multiply(uint8_t x, uint8_t y)\n{\n  return (((y & 1) * x) ^\n       ((y>>1 & 1) * xtime(x)) ^\n       ((y>>2 & 1) * xtime(xtime(x))) ^\n       ((y>>3 & 1) * xtime(xtime(xtime(x)))) ^\n       ((y>>4 & 1) * xtime(xtime(xtime(xtime(x))))));\n  }\n#else\n#define Multiply(x, y)                                \\\n      (  ((y & 1) * x) ^                              \\\n      ((y>>1 & 1) * xtime(x)) ^                       \\\n      ((y>>2 & 1) * xtime(xtime(x))) ^                \\\n      ((y>>3 & 1) * xtime(xtime(xtime(x)))) ^         \\\n      ((y>>4 & 1) * xtime(xtime(xtime(xtime(x))))))   \\\n\n#endif\n\n// MixColumns function mixes the columns of the state matrix.\n// The method used to multiply may be difficult to understand for the inexperienced.\n// Please use the references to gain more information.\nstatic void InvMixColumns(state_t* state)\n{\n  int i;\n  uint8_t a, b, c, d;\n  for (i = 0; i < 4; ++i)\n  {\n    a = (*state)[i][0];\n    b = (*state)[i][1];\n    c = (*state)[i][2];\n    d = (*state)[i][3];\n\n    (*state)[i][0] = Multiply(a, 0x0e) ^ Multiply(b, 0x0b) ^ Multiply(c, 0x0d) ^ Multiply(d, 0x09);\n    (*state)[i][1] = Multiply(a, 0x09) ^ Multiply(b, 0x0e) ^ Multiply(c, 0x0b) ^ Multiply(d, 0x0d);\n    (*state)[i][2] = Multiply(a, 0x0d) ^ Multiply(b, 0x09) ^ Multiply(c, 0x0e) ^ Multiply(d, 0x0b);\n    (*state)[i][3] = Multiply(a, 0x0b) ^ Multiply(b, 0x0d) ^ Multiply(c, 0x09) ^ Multiply(d, 0x0e);\n  }\n}\n\n\n// The SubBytes Function Substitutes the values in the\n// state matrix with values in an S-box.\nstatic void InvSubBytes(state_t* state)\n{\n  uint8_t i, j;\n  for (i = 0; i < 4; ++i)\n  {\n    for (j = 0; j < 4; ++j)\n    {\n      (*state)[j][i] = getSBoxInvert((*state)[j][i]);\n    }\n  }\n}\n\nstatic void InvShiftRows(state_t* state)\n{\n  uint8_t temp;\n\n  // Rotate first row 1 columns to right\n  temp = (*state)[3][1];\n  (*state)[3][1] = (*state)[2][1];\n  (*state)[2][1] = (*state)[1][1];\n  (*state)[1][1] = (*state)[0][1];\n  (*state)[0][1] = temp;\n\n  // Rotate second row 2 columns to right\n  temp = (*state)[0][2];\n  (*state)[0][2] = (*state)[2][2];\n  (*state)[2][2] = temp;\n\n  temp = (*state)[1][2];\n  (*state)[1][2] = (*state)[3][2];\n  (*state)[3][2] = temp;\n\n  // Rotate third row 3 columns to right\n  temp = (*state)[0][3];\n  (*state)[0][3] = (*state)[1][3];\n  (*state)[1][3] = (*state)[2][3];\n  (*state)[2][3] = (*state)[3][3];\n  (*state)[3][3] = temp;\n}\n\n\n// Cipher is the main function that encrypts the PlainText.\nstatic void Cipher(state_t* state, uint8_t* RoundKey)\n{\n  uint8_t round = 0;\n\n  // Add the First round key to the state before starting the rounds.\n  AddRoundKey(0, state, RoundKey);\n\n  // There will be Nr rounds.\n  // The first Nr-1 rounds are identical.\n  // These Nr-1 rounds are executed in the loop below.\n  for (round = 1; round < Nr; ++round)\n  {\n    SubBytes(state);\n    ShiftRows(state);\n    MixColumns(state);\n    AddRoundKey(round, state, RoundKey);\n  }\n\n  // The last round is given below.\n  // The MixColumns function is not here in the last round.\n  SubBytes(state);\n  ShiftRows(state);\n  AddRoundKey(Nr, state, RoundKey);\n}\n\nstatic void InvCipher(state_t* state,uint8_t* RoundKey)\n{\n  uint8_t round = 0;\n\n  // Add the First round key to the state before starting the rounds.\n  AddRoundKey(Nr, state, RoundKey);\n\n  // There will be Nr rounds.\n  // The first Nr-1 rounds are identical.\n  // These Nr-1 rounds are executed in the loop below.\n  for (round = (Nr - 1); round > 0; --round)\n  {\n    InvShiftRows(state);\n    InvSubBytes(state);\n    AddRoundKey(round, state, RoundKey);\n    InvMixColumns(state);\n  }\n\n  // The last round is given below.\n  // The MixColumns function is not here in the last round.\n  InvShiftRows(state);\n  InvSubBytes(state);\n  AddRoundKey(0, state, RoundKey);\n}\n\n\n/*****************************************************************************/\n/* Public functions:                                                         */\n/*****************************************************************************/\n#if defined(ECB) && (ECB == 1)\n\n\nvoid AES_ECB_encrypt(struct AES_ctx *ctx,const uint8_t* buf)\n{\n  // The next function call encrypts the PlainText with the Key using AES algorithm.\n  Cipher((state_t*)buf, ctx->RoundKey);\n}\n\nvoid AES_ECB_decrypt(struct AES_ctx* ctx,const uint8_t* buf)\n{\n  // The next function call decrypts the PlainText with the Key using AES algorithm.\n  InvCipher((state_t*)buf, ctx->RoundKey);\n}\n\n\n#endif // #if defined(ECB) && (ECB == 1)\n\n\n\n\n\n#if defined(CBC) && (CBC == 1)\n\n\nstatic void XorWithIv(uint8_t* buf, uint8_t* Iv)\n{\n  uint8_t i;\n  for (i = 0; i < AES_BLOCKLEN; ++i) // The block in AES is always 128bit no matter the key size\n  {\n    buf[i] ^= Iv[i];\n  }\n}\n\nvoid AES_CBC_encrypt_buffer(struct AES_ctx *ctx,uint8_t* buf, uint32_t length)\n{\n  uintptr_t i;\n  uint8_t *Iv = ctx->Iv;\n  for (i = 0; i < length; i += AES_BLOCKLEN)\n  {\n    XorWithIv(buf, Iv);\n    Cipher((state_t*)buf, ctx->RoundKey);\n    Iv = buf;\n    buf += AES_BLOCKLEN;\n    //printf(\"Step %d - %d\", i/16, i);\n  }\n  /* store Iv in ctx for next call */\n  memcpy(ctx->Iv, Iv, AES_BLOCKLEN);\n}\n\nvoid AES_CBC_decrypt_buffer(struct AES_ctx* ctx, uint8_t* buf,  uint32_t length)\n{\n  uintptr_t i;\n  uint8_t storeNextIv[AES_BLOCKLEN];\n  for (i = 0; i < length; i += AES_BLOCKLEN)\n  {\n    memcpy(storeNextIv, buf, AES_BLOCKLEN);\n    InvCipher((state_t*)buf, ctx->RoundKey);\n    XorWithIv(buf, ctx->Iv);\n    memcpy(ctx->Iv, storeNextIv, AES_BLOCKLEN);\n    buf += AES_BLOCKLEN;\n  }\n\n}\n\n#endif // #if defined(CBC) && (CBC == 1)\n\n\n\n#if defined(CTR) && (CTR == 1)\n\n/* Symmetrical operation: same function for encrypting as for decrypting. Note any IV/nonce should never be reused with the same key */\nvoid AES_CTR_xcrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, uint32_t length)\n{\n  uint8_t buffer[AES_BLOCKLEN];\n\n  unsigned i;\n  int bi;\n  for (i = 0, bi = AES_BLOCKLEN; i < length; ++i, ++bi)\n  {\n    if (bi == AES_BLOCKLEN) /* we need to regen xor compliment in buffer */\n    {\n\n      memcpy(buffer, ctx->Iv, AES_BLOCKLEN);\n      Cipher((state_t*)buffer,ctx->RoundKey);\n\n      /* Increment Iv and handle overflow */\n      for (bi = (AES_BLOCKLEN - 1); bi >= 0; --bi)\n      {\n\t/* inc will owerflow */\n        if (ctx->Iv[bi] == 255)\n\t{\n          ctx->Iv[bi] = 0;\n          continue;\n        }\n        ctx->Iv[bi] += 1;\n        break;\n      }\n      bi = 0;\n    }\n\n    buf[i] = (buf[i] ^ buffer[bi]);\n  }\n}\n\n#endif // #if defined(CTR) && (CTR == 1)\n\n"
  },
  {
    "path": "tests/test_tools/aes.h",
    "content": "#ifndef _AES_H_\n#define _AES_H_\n\n/*\n * This AES implementation is contributed by https://github.com/kokke/tiny-AES-c and just used for testing\n */\n#include <stdint.h>\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif //__cplusplus\n\n// #define the macros below to 1/0 to enable/disable the mode of operation.\n//\n// CBC enables AES encryption in CBC-mode of operation.\n// CTR enables encryption in counter-mode.\n// ECB enables the basic ECB 16-byte block algorithm. All can be enabled simultaneously.\n\n// The #ifndef-guard allows it to be configured before #include'ing or at compile time.\n#ifndef CBC\n  #define CBC 1\n#endif\n\n#ifndef ECB\n  #define ECB 1\n#endif\n\n#ifndef CTR\n  #define CTR 1\n#endif\n\n\n#define AES128 1\n//#define AES192 1\n//#define AES256 1\n\n#define AES_BLOCKLEN 16 //Block length in bytes AES is 128b block only\n\n#if defined(AES256) && (AES256 == 1)\n    #define AES_KEYLEN 32\n    #define AES_keyExpSize 240\n#elif defined(AES192) && (AES192 == 1)\n    #define AES_KEYLEN 24\n    #define AES_keyExpSize 208\n#else\n    #define AES_KEYLEN 16   // Key length in bytes\n    #define AES_keyExpSize 176\n#endif\n\nstruct AES_ctx\n{\n  uint8_t RoundKey[AES_keyExpSize];\n#if (defined(CBC) && (CBC == 1)) || (defined(CTR) && (CTR == 1))\n  uint8_t Iv[AES_BLOCKLEN];\n#endif\n};\n\nvoid AES_init_ctx(struct AES_ctx* ctx, const uint8_t* key);\n#if (defined(CBC) && (CBC == 1)) || (defined(CTR) && (CTR == 1))\nvoid AES_init_ctx_iv(struct AES_ctx* ctx, const uint8_t* key, const uint8_t* iv);\nvoid AES_ctx_set_iv(struct AES_ctx* ctx, const uint8_t* iv);\n#endif\n\n#if defined(ECB) && (ECB == 1)\n// buffer size is exactly AES_BLOCKLEN bytes;\n// you need only AES_init_ctx as IV is not used in ECB\n// NB: ECB is considered insecure for most uses\nvoid AES_ECB_encrypt(struct AES_ctx* ctx, const uint8_t* buf);\nvoid AES_ECB_decrypt(struct AES_ctx* ctx, const uint8_t* buf);\n\n#endif // #if defined(ECB) && (ECB == !)\n\n\n#if defined(CBC) && (CBC == 1)\n// buffer size MUST be mutile of AES_BLOCKLEN;\n// Suggest https://en.wikipedia.org/wiki/Padding_(cryptography)#PKCS7 for padding scheme\n// NOTES: you need to set IV in ctx via AES_init_ctx_iv() or AES_ctx_set_iv()\n//        no IV should ever be reused with the same key\nvoid AES_CBC_encrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, uint32_t length);\nvoid AES_CBC_decrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, uint32_t length);\n\n#endif // #if defined(CBC) && (CBC == 1)\n\n\n#if defined(CTR) && (CTR == 1)\n\n// Same function for encrypting as for decrypting.\n// IV is incremented for every block, and used after encryption as XOR-compliment for output\n// Suggesting https://en.wikipedia.org/wiki/Padding_(cryptography)#PKCS7 for padding scheme\n// NOTES: you need to set IV in ctx with AES_init_ctx_iv() or AES_ctx_set_iv()\n//        no IV should ever be reused with the same key\nvoid AES_CTR_xcrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, uint32_t length);\n\n#endif // #if defined(CTR) && (CTR == 1)\n\n#ifdef __cplusplus\n}\n#endif //__cplusplus\n\n#endif //_AES_H_\n"
  },
  {
    "path": "tests/test_tools/attribute_io.cpp",
    "content": "#include \"attribute_io.hpp\"\n\n#include <ostream>\n\n\nstd::ostream& bluetoe::details::operator<<( std::ostream& out, const bluetoe::details::attribute_access_result& result )\n{\n    switch ( result )\n    {\n        case attribute_access_result::success:\n            out << \"success\";\n            break;\n\n        case attribute_access_result::invalid_offset:\n            out << \"invalid_offset\";\n            break;\n\n        case attribute_access_result::write_not_permitted:\n            out << \"write_not_permitted\";\n            break;\n\n        case attribute_access_result::read_not_permitted:\n            out << \"read_not_permitted\";\n            break;\n\n        case attribute_access_result::invalid_attribute_value_length:\n            out << \"invalid_attribute_value_length\";\n            break;\n\n        case attribute_access_result::attribute_not_long:\n            out << \"attribute_not_long\";\n            break;\n\n        case attribute_access_result::request_not_supported:\n            out << \"request_not_supported\";\n            break;\n\n        case attribute_access_result::insufficient_encryption:\n            out << \"insufficient_encryption\";\n            break;\n\n        case attribute_access_result::insufficient_authentication:\n            out << \"insufficient_authentication\";\n            break;\n\n        case attribute_access_result::uuid_equal:\n            out << \"uuid_equal\";\n            break;\n\n        case attribute_access_result::value_equal:\n            out << \"value_equal\";\n            break;\n\n        default:\n            out << \"invalid attribute_access_result(\" << static_cast< int >( result ) << \")\";\n            break;\n    }\n\n    return out;\n}\n\nstd::ostream& bluetoe::details::operator<<( std::ostream& out, notification_type type )\n{\n    switch ( type )\n    {\n        case notification_type::notification:\n            out << \"notification\";\n            break;\n\n        case notification_type::indication:\n            out << \"notification\";\n            break;\n\n        case notification_type::confirmation:\n            out << \"notification\";\n            break;\n\n        default:\n            out << \"invalid notification_type(\" << static_cast< int >( type ) << \")\";\n            break;\n    }\n\n    return out;\n}\n"
  },
  {
    "path": "tests/test_tools/attribute_io.hpp",
    "content": "#ifndef BLUETOE_TESTS_TOOLS_ATTRIBUTE_IO_HPP\n#define BLUETOE_TESTS_TOOLS_ATTRIBUTE_IO_HPP\n\n#include <bluetoe/attribute.hpp>\n\n#include <iosfwd>\n\nnamespace bluetoe {\nnamespace details {\n\n    std::ostream& operator<<( std::ostream&, const attribute_access_result& );\n    std::ostream& operator<<( std::ostream&, notification_type );\n}\n}\n\n#endif\n"
  },
  {
    "path": "tests/test_tools/buffer_io.cpp",
    "content": "#include \"buffer_io.hpp\"\n#include \"hexdump.hpp\"\n\n#include <bluetoe/buffer.hpp>\n#include <ostream>\n\nnamespace bluetoe {\nnamespace link_layer {\n\n    std::ostream& operator<<( std::ostream& out, const read_buffer& buffer )\n    {\n        return out << write_buffer{ buffer.buffer, buffer.size };\n    }\n\n    std::ostream& operator<<( std::ostream& out, const write_buffer& buffer )\n    {\n        hex_dump( out, buffer.buffer, buffer.buffer + buffer.size );\n\n        return out;\n    }\n}\n}\n"
  },
  {
    "path": "tests/test_tools/buffer_io.hpp",
    "content": "#ifndef BLUETOE_TESTS_LINK_LAYER_BUFFER_HPP\n#define BLUETOE_TESTS_LINK_LAYER_BUFFER_HPP\n\n#include <iosfwd>\n\nnamespace bluetoe {\nnamespace link_layer {\n\n    struct read_buffer;\n    struct write_buffer;\n\n    std::ostream& operator<<( std::ostream&, const read_buffer& );\n    std::ostream& operator<<( std::ostream&, const write_buffer& );\n}\n}\n\n#endif\n"
  },
  {
    "path": "tests/test_tools/hexdump.cpp",
    "content": "#include \"hexdump.hpp\"\r\n#include <algorithm>\r\n#include <cassert>\r\n\r\nchar as_printable(char maybe_printable)\r\n{\r\n    return ( static_cast<unsigned char>(maybe_printable) > 31\r\n        && static_cast<unsigned char>(maybe_printable) < 127 )\r\n        ? maybe_printable\r\n        : '.';\r\n}\r\n\r\nstd::string as_printable(const std::string& input)\r\n{\r\n    std::string result(input);\r\n    char (*f)(char) = &as_printable;\r\n    std::transform(result.begin(), result.end(), result.begin(), f);\r\n\r\n    return result;\r\n}\r\n\r\nvoid print_hex(std::ostream& out, char value)\r\n{\r\n    print_hex(out, static_cast<unsigned char>(value));\r\n}\r\n\r\nnamespace {\r\n    unsigned char nibble(unsigned char val)\r\n    {\r\n        assert(val < 16);\r\n        return val < 10 ? '0' + val : 'a' + (val - 10);\r\n    }\r\n\r\n    unsigned char upper_nibble(unsigned char val)\r\n    {\r\n        assert(val < 16);\r\n        return val < 10 ? '0' + val : 'A' + (val - 10);\r\n    }\r\n}\r\n\r\nvoid print_hex(std::ostream& out, unsigned char value)\r\n{\r\n    out << nibble(value >> 4) << nibble(value & 0xf);\r\n}\r\n\r\nvoid print_hex_uppercase( std::ostream& out, unsigned char value )\r\n{\r\n    out << upper_nibble( value >> 4 ) << upper_nibble( value & 0xf );\r\n}\r\n\r\nvoid hex_dump(std::ostream& output,const void* object, std::size_t object_size)\r\n{\r\n    hex_dump(output, static_cast<const char*>(object), static_cast<const char*>(object) + object_size);\r\n}\r\n\r\n"
  },
  {
    "path": "tests/test_tools/hexdump.hpp",
    "content": "#ifndef FAG_TOOLS_HEXDUMP_HPP\r\n#define FAG_TOOLS_HEXDUMP_HPP\r\n\r\n#include <string>\r\n#include <ostream>\r\n#include <sstream>\r\n\r\n/**\r\n * @brief returns an ascii encoded character that is printable\r\n *\r\n * If the input char is not printable, a '.' is returned otherwise\r\n * the char it self.\r\n */\r\nchar as_printable(char maybe_printable);\r\n\r\n/**\r\n * @brief returns a string where none printable chars are replaced by a dot ('.').\r\n */\r\nstd::string as_printable(const std::string& input);\r\n\r\n/**\r\n * @brief prints a byte as a hex text on the given stream\r\n */\r\nvoid print_hex(std::ostream& out, char value);\r\nvoid print_hex(std::ostream& out, unsigned char value);\r\n\r\n/** @copydoc print_hex(std::ostream&, char) */\r\nvoid print_hex_uppercase(std::ostream& out, unsigned char value);\r\n\r\n/**\r\n * @brief prints a character sequence as a hex dump\r\n *\r\n * The sequence given by [begin, end) is printed in lines\r\n * of 16 chars, by first printing there hex values with\r\n * white spaces seperated followed by a textual representation.\r\n */\r\ntemplate <class Iter>\r\nvoid hex_dump(std::ostream& out, Iter begin, Iter end)\r\n{\r\n    static const unsigned   page_width = 16;\r\n    unsigned                char_cnt   = page_width;\r\n    Iter                    line_start = begin;\r\n\r\n    for ( ; begin != end && out; )\r\n    {\r\n        print_hex(out, *begin);\r\n        out << ' ';\r\n        ++begin;\r\n\r\n        if ( --char_cnt == 0 || begin == end )\r\n        {\r\n            // fill rest of the line\r\n            for ( ; char_cnt != 0; --char_cnt)\r\n                out << \"   \";\r\n\r\n            for ( ; line_start != begin; ++line_start )\r\n                out << as_printable(*line_start);\r\n\r\n            out << '\\n';\r\n            char_cnt   = page_width;\r\n        }\r\n    }\r\n}\r\n\r\n/**\r\n * @brief converts a character sequence into a hex-dump\r\n *\r\n * this functions calls the function above with a stringstream\r\n * and returns the result as a text.\r\n */\r\ntemplate <class Iter>\r\nstd::string hex_dump(Iter begin, Iter end)\r\n{\r\n    std::ostringstream out;\r\n    hex_dump(out, begin, end);\r\n\r\n    return out.str();\r\n}\r\n\r\n\r\n/**\r\n * @brief creates a hexdump of the given object\r\n *\r\n * @param output the output, where the hexdump is made\r\n * @param object the adress of the object to be dumped\r\n * @param object_size the object size\r\n */\r\nvoid hex_dump(std::ostream& output, const void* object, std::size_t object_size);\r\n\r\n\r\n#endif //FAG_TOOLS_HEXDUMP_HPP\r\n\r\n"
  },
  {
    "path": "tests/test_tools/pairing_status_io.cpp",
    "content": "#include \"pairing_status_io.hpp\"\n\n#include <ostream>\n\nnamespace bluetoe {\n\n    std::ostream& operator<<( std::ostream& output, device_pairing_status status )\n    {\n        switch ( status )\n        {\n        case device_pairing_status::no_key:\n            return output << \"no_key\";\n        case device_pairing_status::unauthenticated_key:\n            return output << \"unauthenticated_key\";\n        case device_pairing_status::authenticated_key:\n            return output << \"authenticated_key\";\n        case device_pairing_status::authenticated_key_with_secure_connection:\n            return output << \"authenticated_key_with_secure_connection\";\n        }\n\n        return output << \"invalid device_pairing_status-value (\" << static_cast< int >( status ) << \")\";\n    }\n}\n"
  },
  {
    "path": "tests/test_tools/pairing_status_io.hpp",
    "content": "#ifndef BLUETOE_TEST_PAIRING_STATUS_HPP\n#define BLUETOE_TEST_PAIRING_STATUS_HPP\n\n#include <bluetoe/pairing_status.hpp>\n\n#include <iosfwd>\n\nnamespace bluetoe {\n\n    std::ostream& operator<<( std::ostream& output, device_pairing_status status );\n}\n\n#endif // include guard\n\n\n"
  },
  {
    "path": "tests/test_tools/test_layout.hpp",
    "content": "#ifndef BLUETOE_TESTS_TEST_TOOLS_TEST_LAYOUT_HPP\n#define BLUETOE_TESTS_TEST_TOOLS_TEST_LAYOUT_HPP\n\n#include <bluetoe/buffer.hpp>\n#include <bluetoe/bits.hpp>\n\n#include <cstddef>\n#include <cstdint>\n\nnamespace test {\n    template < std::size_t Overhead >\n    struct layout_with_overhead\n    {\n        static constexpr std::size_t header_size = sizeof( std::uint16_t );\n\n        static std::uint16_t header( const std::uint8_t* pdu )\n        {\n            return ::bluetoe::details::read_16bit( pdu );\n        }\n\n        static void header( std::uint8_t* pdu, std::uint16_t header_value )\n        {\n            ::bluetoe::details::write_16bit( pdu, header_value );\n        }\n\n        static std::uint16_t header( const bluetoe::link_layer::read_buffer& pdu )\n        {\n            assert( pdu.size >= data_channel_pdu_memory_size( 0 ) );\n\n            return header( pdu.buffer );\n        }\n\n        static std::uint16_t header( const bluetoe::link_layer::write_buffer& pdu )\n        {\n            assert( pdu.size >= data_channel_pdu_memory_size( 0 ) );\n\n            return header( pdu.buffer );\n        }\n\n        static void header( const bluetoe::link_layer::read_buffer& pdu, std::uint16_t header_value )\n        {\n            assert( pdu.size >= data_channel_pdu_memory_size( 0 ) );\n\n            header( pdu.buffer, header_value );\n        }\n\n        static std::pair< std::uint8_t*, std::uint8_t* > body( const bluetoe::link_layer::read_buffer& pdu )\n        {\n            assert( pdu.size >= header_size );\n\n            return { &pdu.buffer[ header_size + Overhead ], &pdu.buffer[ pdu.size ] };\n        }\n\n        static std::pair< const std::uint8_t*, const std::uint8_t* > body( const bluetoe::link_layer::write_buffer& pdu )\n        {\n            assert( pdu.size >= header_size );\n\n            return { &pdu.buffer[ header_size + Overhead ], &pdu.buffer[ pdu.size ] };\n        }\n\n        static constexpr std::size_t data_channel_pdu_memory_size( std::size_t payload_size )\n        {\n            return header_size + Overhead + payload_size;\n        }\n    };\n}\n\n#endif\n"
  },
  {
    "path": "tests/test_tools/test_radio.cpp",
    "content": "#include \"test_radio.hpp\"\n#include \"hexdump.hpp\"\n\n#include <boost/test/unit_test.hpp>\n\nnamespace test {\n\n    std::ostream& operator<<( std::ostream& out, const advertising_data& data )\n    {\n        out << \"at: \" << data.schedule_time << \"; scheduled: \" << data.transmision_time << \"; channel: \" << data.channel;\n        out << \"\\ndata:\\n\" << hex_dump( data.transmitted_data.begin(), data.transmitted_data.end() );\n\n        return out;\n    }\n\n    std::ostream& operator<<( std::ostream& out, const std::vector< advertising_data >& data )\n    {\n        for ( const auto& a : data )\n            out << a << \"\\n\";\n\n        return out;\n    }\n\n    std::ostream& operator<<( std::ostream& out, const connection_event_response& rsp )\n    {\n        if ( rsp.timeout )\n        {\n            out << \"response-timeout\";\n        }\n        else if ( rsp.data.size() )\n        {\n            out << \"\\ndata:\\n\";\n\n            for ( const auto& pdu: rsp.data )\n            {\n                hex_dump( out, pdu.begin(), pdu.end() );\n            }\n        }\n        else if ( rsp.func )\n        {\n            out << \"func()\";\n        }\n        else\n        {\n            out << \"??empty??\";\n        }\n\n        return out;\n    }\n\n    static void head_info( std::ostream& out, const pdu_t& pdu )\n    {\n        if ( pdu.size() < 2 )\n        {\n            out << \"?\\n\";\n            return;\n        }\n\n        const std::uint8_t  llid    = pdu[ 0 ] & 3;\n        const bool          nesn    = pdu[ 0 ] & 4;\n        const bool          sn      = pdu[ 0 ] & 8;\n        const bool          md      = pdu[ 0 ] & 16;\n        const bool          rfu     = pdu[ 0 ] & 0xe0;\n        const bool          enc     = pdu.encrypted;\n\n        out << \"llid: \" << (int)llid;\n        out << \" ne: \" << nesn << \" sn: \" << sn;\n\n        if ( md )\n            out << \" md: 1\";\n\n        if ( enc )\n            out << \" enc: 1\";\n\n        if ( rfu )\n            out << \" rfu!!!\";\n\n        if ( pdu.size() -2 != pdu[ 1 ] )\n            out << \" SIZE!!!: \" << (int)pdu[ 1 ];\n\n        out << \"\\n\";\n    }\n\n    std::ostream& operator<<( std::ostream& out, const connection_event& data )\n    {\n        out << \"schedule_time: \" << data.schedule_time << \"; channel: \" << data.channel\n            << \"\\nstart_receive: \" << data.start_receive << \"; end_receive: \" << data.end_receive << \"; connection_interval: \" << data.connection_interval\n            << \"\\nc->p: \" << data.receiving_encoding << \"; p->: \" << data.transmission_encoding\n            << \"; rx-encrypt: \" << data.receive_encryption_at_start_of_event << \"; tx-encrypt: \" << data.transmit_encryption_at_start_of_event\n            << \"\\nreceived_data:\\n\";\n\n        for ( const auto& pdu: data.received_data )\n        {\n            head_info( out, pdu );\n            hex_dump( out, pdu.begin(), pdu.end() );\n        }\n\n        out << \"transmitted_data:\\n\";\n        for ( const auto& pdu: data.transmitted_data )\n        {\n            head_info( out, pdu );\n            hex_dump( out, pdu.begin(), pdu.end() );\n        }\n\n        return out;\n    }\n\n    std::ostream& operator<<( std::ostream& out, const std::vector< connection_event >& list )\n    {\n        for ( const auto& c : list )\n            out << c << \"\\n\";\n\n        return out;\n    }\n\n    std::ostream& operator<<( std::ostream& out, const pdu_t& data )\n    {\n        hex_dump( out, data.begin(), data.end() );\n\n        return out;\n    }\n\n    std::ostream& operator<<( std::ostream& out, const pdu_list_t& data )\n    {\n        for ( const auto& p : data )\n            hex_dump( out, p.begin(), p.end() );\n\n        return out;\n    }\n\n    std::ostream& operator<<( std::ostream& out, bluetoe::link_layer::phy_ll_encoding::phy_ll_encoding_t phy )\n    {\n        switch ( phy )\n        {\n            case bluetoe::link_layer::phy_ll_encoding::phy_ll_encoding_t::le_1m_phy:\n                out << \"1M\";\n                break;\n\n            case bluetoe::link_layer::phy_ll_encoding::phy_ll_encoding_t::le_2m_phy:\n                out << \"2M\";\n                break;\n\n            case bluetoe::link_layer::phy_ll_encoding::phy_ll_encoding_t::le_coded_phy:\n                out << \"CODED\";\n                break;\n\n            default:\n                out << \"invalid phy_ll_encoding_t(\" << static_cast< int >( phy ) << \")\";\n        }\n        return out;\n    }\n\n    bool check_pdu( const pdu_t& pdu, std::initializer_list< std::uint16_t > pattern )\n    {\n        std::size_t pos = 0;\n        for ( ; pos != pattern.size() && pos != pdu.size(); ++pos )\n        {\n            const std::uint16_t patt = *( pattern.begin() + pos );\n            const std::uint8_t  data = pdu[ pos ];\n\n            if ( patt == and_so_on )\n                return true;\n\n            if ( patt != X && patt != data )\n                return false;\n        }\n\n        // a trailing \"and_so_on\"\n        if ( pos == pdu.size() && pos < pattern.size() && *( pattern.begin() + pos ) == and_so_on )\n            return true;\n\n        return pos == pattern.size() && pos == pdu.size();\n    }\n\n    std::string pretty_print_pattern( std::initializer_list< std::uint16_t > pattern )\n    {\n        static constexpr std::size_t line_width = 16;\n\n        std::ostringstream out;\n        std::size_t width = line_width;\n\n        for ( auto begin = pattern.begin(); begin != pattern.end(); )\n        {\n            if ( *begin == X )\n            {\n                out << \"XX\";\n            }\n            else if ( *begin == and_so_on )\n            {\n                out << \"...\";\n            }\n            else\n            {\n                print_hex( out, static_cast< std::uint8_t >( *begin ) );\n            }\n\n            ++begin;\n            --width;\n\n            if ( begin != pattern.end() )\n            {\n                if ( width )\n                {\n                    out << ' ';\n                }\n                else\n                {\n                    out << '\\n';\n                    width = line_width;\n                }\n            }\n        }\n\n        return out.str();\n    }\n\n    advertising_response::advertising_response()\n        : channel( 0 )\n        , delay( bluetoe::link_layer::delta_time( 0 ) )\n        , has_crc_error( false )\n    {\n    }\n\n    advertising_response::advertising_response( unsigned c, std::vector< std::uint8_t > d, const bluetoe::link_layer::delta_time l )\n        : channel( c )\n        , received_data( d )\n        , delay( l )\n        , has_crc_error( false )\n    {\n    }\n\n    advertising_response advertising_response::crc_error()\n    {\n        advertising_response result;\n        result.has_crc_error = true;\n\n        return result;\n    }\n\n    std::ostream& operator<<( std::ostream& out, const advertising_response& data )\n    {\n        out << \"channel: \" << data.channel << \"; delayed: \" << data.delay;\n        out << \"\\ndata:\\n\" << hex_dump( data.received_data.begin(), data.received_data.end() );\n\n        return out;\n    }\n\n    std::ostream& operator<<( std::ostream& out, const scheduled_user_timer& data )\n    {\n        out << \"schedule_time: \" << data.schedule_time << \"; delayed: \" << data.delay;\n\n        return out;\n    }\n\n    std::ostream& operator<<( std::ostream& out, const std::vector< scheduled_user_timer >& data )\n    {\n        for ( const auto& d: data )\n            out << d << \"\\n\";\n\n        return out;\n    }\n\n    const std::vector< advertising_data >& radio_base::advertisings() const\n    {\n        return advertised_data_;\n    }\n\n    const std::vector< connection_event >& radio_base::connection_events() const\n    {\n        return connection_events_;\n    }\n\n    const std::vector< scheduled_user_timer >& radio_base::scheduled_user_timers() const\n    {\n        return scheduled_user_timers_;\n    }\n\n    radio_base::radio_base()\n        : access_address_and_crc_valid_( false )\n        , receiving_encoding_( bluetoe::link_layer::phy_ll_encoding::le_1m_phy )\n        , transmiting_encoding_( bluetoe::link_layer::phy_ll_encoding::le_1m_phy )\n        , eos_( bluetoe::link_layer::delta_time::seconds( 10 ) )\n    {\n    }\n\n    void radio_base::check_scheduling( const std::function< bool ( const advertising_data& ) >& check, const char* ) const\n    {\n        unsigned n = 0;\n\n        for ( const advertising_data& data : advertised_data_ )\n        {\n            if ( !check( data ) )\n            {\n                boost::test_tools::predicate_result result( false );\n                result.message() << \"\\nfor \" << ( n + 1 ) << \"th scheduled action \" << data;\n                BOOST_CHECK( result );\n                return;\n            }\n\n            ++n;\n        }\n    }\n\n    void radio_base::check_scheduling( const std::function< bool ( const advertising_data& first, const advertising_data& next ) >& check, const char* message ) const\n    {\n        check_scheduling(\n            [&]( const advertising_data& ) { return true; },\n            check,\n            message\n        );\n    }\n\n    void radio_base::check_scheduling( const std::function< bool ( const advertising_data& ) >& filter, const std::function< bool ( const advertising_data& first, const advertising_data& next ) >& check, const char* message ) const\n    {\n        pair_wise_check(\n            filter,\n            check,\n            [&]( advertising_list::const_iterator first, advertising_list::const_iterator next )\n            {\n                const auto n  = std::distance( advertised_data_.begin(), first ) + 1;\n                const auto nn = std::distance( first, next ) + n;\n\n                boost::test_tools::predicate_result result( false );\n                result.message() << \"\\nfor \" << n << \"th and \" << nn << \"th scheduled action\";\n                result.message() << \"\\nTesting: \\\"\" << message << \"\\\" failed.\";\n                result.message() << \"\\n\" << n << \"th scheduled action, \" << *first;\n                result.message() << \"\\n\" << nn << \"th scheduled action, \" << *next;\n                BOOST_CHECK( result );\n            }\n        );\n    }\n\n    void radio_base::check_scheduling( const std::function< bool ( const advertising_data& ) >& filter, const std::function< bool ( const advertising_data& data ) >& check, const char* message ) const\n    {\n        check_scheduling(\n            [&]( const advertising_data& data ) -> bool\n            {\n                return !filter( data ) || check( data );\n            },\n            message\n        );\n    }\n\n    void radio_base::check_first_scheduling( const std::function< bool ( const advertising_data& ) >& filter, const std::function< bool ( const advertising_data& data ) >& check, const char* message ) const\n    {\n        bool ignore = false;\n        check_scheduling(\n            [&ignore, filter]( const advertising_data& d )\n            {\n                const bool result = !ignore && filter( d );\n                ignore = true;\n\n                return result;\n            },\n            check,\n            message\n        );\n    }\n\n    void radio_base::find_scheduling( const std::function< bool ( const advertising_data& ) >& filter, const char* message ) const\n    {\n        unsigned found = 0;\n\n        for ( const advertising_data& data : advertised_data_ )\n        {\n            if ( filter( data ) )\n                ++found;\n        }\n\n        if ( found != 1u )\n        {\n            boost::test_tools::predicate_result result( false );\n            if ( found )\n            {\n                result.message() << message << \": required to find only in scheduling, but found: \" << found;\n            }\n            else\n            {\n                result.message() << message << \": no required scheduling found!\";\n            }\n            BOOST_CHECK( result );\n        }\n    }\n\n    void radio_base::find_scheduling( const std::function< bool ( const advertising_data& first, const advertising_data& next ) >& check, const char* message ) const\n    {\n        int count = 0;\n\n        all_data(\n            []( const advertising_data& ){ return true; },\n            [ &count, &check ]( const advertising_data& first, const advertising_data& next )\n            {\n                if ( check( first, next ) )\n                    ++count;\n            }\n        );\n\n        if ( count != 1 )\n        {\n            boost::test_tools::predicate_result result( false );\n            if ( count == 0 )\n            {\n                result.message() << message << \": no required scheduling found!\";\n            }\n            else\n            {\n                result.message() << message << \": required to find only in scheduling, but found: \" << count;\n            }\n            BOOST_CHECK( result );\n        }\n    }\n\n    void radio_base::radio_set_phy(\n        bluetoe::link_layer::phy_ll_encoding::phy_ll_encoding_t receiving_encoding,\n        bluetoe::link_layer::phy_ll_encoding::phy_ll_encoding_t transmiting_encoding )\n    {\n        if ( receiving_encoding != bluetoe::link_layer::phy_ll_encoding::le_unchanged_coding )\n            receiving_encoding_ = receiving_encoding;\n\n        if ( transmiting_encoding != bluetoe::link_layer::phy_ll_encoding::le_unchanged_coding )\n            transmiting_encoding_ = transmiting_encoding;\n    }\n\n    std::vector< advertising_data >::const_iterator radio_base::next( std::vector< advertising_data >::const_iterator first, const std::function< bool ( const advertising_data& ) >& filter ) const\n    {\n        while ( first != advertised_data_.end() && !filter( *first ) )\n            ++first;\n\n        return first;\n    }\n\n    void radio_base::pair_wise_check(\n        const std::function< bool ( const advertising_data& ) >&                                               filter,\n        const std::function< bool ( const advertising_data& first, const advertising_data& next ) >&              check,\n        const std::function< void ( advertising_list::const_iterator first, advertising_list::const_iterator next ) >&    fail ) const\n    {\n        for ( auto data = next( advertised_data_.begin(), filter ); data != advertised_data_.end(); )\n        {\n            const auto next_data = next( data +1, filter );\n\n            if ( next_data != advertised_data_.end() )\n            {\n                if ( !check( *data, *next_data ) )\n                {\n                    fail( data, next_data );\n                    return;\n                }\n            }\n\n            data = next_data;\n        }\n    }\n\n    void radio_base::all_data( std::function< void ( const advertising_data& ) > f ) const\n    {\n        for ( const advertising_data& data : advertised_data_ )\n            f( data );\n    }\n\n    void radio_base::all_data(\n        const std::function< bool ( const advertising_data& ) >& filter,\n        const std::function< void ( const advertising_data& first, const advertising_data& next ) >& iter ) const\n    {\n        for ( auto data = next( advertised_data_.begin(), filter ); data != advertised_data_.end(); )\n        {\n            const auto next_data = next( data +1, filter );\n\n            if ( next_data != advertised_data_.end() )\n            {\n                iter( *data, *next_data );\n            }\n\n            data = next_data;\n        }\n    }\n\n    unsigned radio_base::count_data( const std::function< bool ( const advertising_data& ) >& filter ) const\n    {\n        return sum_data< unsigned >(\n            [filter]( const advertising_data& data, unsigned count )\n            {\n                return filter( data )\n                    ? count + 1\n                    : count;\n            }, 0u\n        );\n    }\n\n    void radio_base::add_responder( const advertising_responder_t& responder )\n    {\n        responders_.push_back( responder );\n    }\n\n    void radio_base::respond_to( unsigned channel, std::initializer_list< std::uint8_t > pdu )\n    {\n        respond_to( channel, std::vector< std::uint8_t >( pdu ) );\n    }\n\n    void radio_base::respond_to( unsigned channel, std::vector< std::uint8_t > pdu )\n    {\n        assert( channel < 40 );\n\n        add_responder(\n            [=]( const advertising_data& d ) -> std::pair< bool, advertising_response >\n            {\n                return std::pair< bool, advertising_response >(\n                    d.channel == channel,\n                    advertising_response{ channel, pdu, T_IFS }\n                );\n            }\n        );\n    }\n\n    void radio_base::respond_to( unsigned channel, std::initializer_list< std::uint8_t > pdu, unsigned times )\n    {\n        for ( ;times; --times )\n            respond_to( channel, pdu );\n    }\n\n    void radio_base::respond_with_crc_error( unsigned channel )\n    {\n        assert( channel < 40 );\n        static_cast< void >( channel );\n\n        add_responder(\n            [=]( const advertising_data& ) -> std::pair< bool, advertising_response >\n            {\n                return std::pair< bool, advertising_response >(\n                    true,\n                    advertising_response::crc_error()\n                );\n            }\n        );\n    }\n\n    std::pair< bool, advertising_response > radio_base::find_response( const advertising_data& data )\n    {\n        std::pair< bool, advertising_response > result( false, advertising_response{} );\n\n        for ( auto f = responders_.begin(); f != responders_.end(); ++f )\n        {\n            result = (*f)( data );\n\n            if ( result.first )\n            {\n                responders_.erase( f );\n\n                return result;\n            }\n        }\n\n        return result;\n    }\n\n    void radio_base::set_access_address_and_crc_init( std::uint32_t access_address, std::uint32_t crc_init )\n    {\n        access_address_ = access_address;\n        crc_init_       = crc_init;\n\n        access_address_and_crc_valid_ = true;\n    }\n\n    std::uint32_t radio_base::access_address() const\n    {\n        assert( access_address_and_crc_valid_ );\n\n        return access_address_;\n    }\n\n    std::uint32_t radio_base::crc_init() const\n    {\n        assert( access_address_and_crc_valid_ );\n\n        return crc_init_;\n    }\n\n    void radio_base::add_connection_event_respond( const connection_event_response& resp )\n    {\n        connection_events_response_.push_back( resp );\n    }\n\n    void radio_base::add_connection_event_respond( std::initializer_list< std::uint8_t > pdu )\n    {\n        add_connection_event_respond(\n            connection_event_response( pdu_list_t( 1, pdu ) ) );\n    }\n\n    void radio_base::add_connection_event_respond( std::function< void() > f )\n    {\n        add_connection_event_respond( connection_event_response( f ) );\n    }\n\n    void radio_base::add_connection_event_respond_timeout()\n    {\n        add_connection_event_respond( connection_event_response() );\n    }\n\n    void radio_base::check_connection_events( const std::function< bool ( const connection_event& ) >& filter, const std::function< bool ( const connection_event& ) >& check, const char* message )\n    {\n        for ( const auto& event : connection_events_ )\n        {\n            if ( filter( event ) && !check( event ) )\n            {\n                boost::test_tools::predicate_result result( false );\n                result.message() << message << \": \" << event;\n                BOOST_CHECK( result );\n            }\n        }\n    }\n\n    void radio_base::check_connection_events( const std::function< bool ( const connection_event& ) >& check, const char* message )\n    {\n        check_connection_events( []( const connection_event& ) -> bool { return true; }, check, message );\n    }\n\n    static const auto filter_l2cap = []( pdu_t& pdu ) -> bool {\n        if ( pdu.size() >= 2 && ( pdu[ 0 ] & 0x03 ) == 0x02 )\n        {\n            pdu.data.erase( pdu.data.begin(), pdu.data.begin() + 2 );\n            return true;\n        }\n\n        return false;\n    };\n\n    static const auto filter_ll = []( pdu_t& pdu ) -> bool {\n        if ( pdu.size() >= 2 && ( pdu[ 0 ] & 0x03 ) == 0x03 )\n        {\n            pdu.data.erase( pdu.data.begin(), pdu.data.begin() + 2 );\n            return true;\n        }\n\n        return false;\n    };\n\n    template < class Filter, class Events, class Pattern >\n    static const std::vector< connection_event > filter_events( const Filter& filter, const Events& events, const Pattern& pattern )\n    {\n        std::vector< connection_event > matching_events;\n\n        for ( const auto& event : events )\n        {\n            for ( auto pdu : event.transmitted_data )\n            {\n                if ( filter( pdu ) && check_pdu( pdu, pattern ) )\n                    matching_events.push_back( event );\n            }\n        }\n\n        return matching_events;\n    }\n\n    template < class Events, class Pattern >\n    static void check_single_event( const Events& matching_events, const char* msg0, const char* msg_multiple, const Pattern& pattern )\n    {\n        if ( matching_events.size() == 0 )\n        {\n            boost::test_tools::predicate_result result( false );\n            result.message() << msg0 << pretty_print_pattern( pattern );\n            BOOST_CHECK( result );\n        }\n        else if ( matching_events.size() != 1 )\n        {\n            boost::test_tools::predicate_result result( false );\n            result.message() << msg_multiple << pretty_print_pattern( pattern ) << \":\\n\\n\";\n\n            for ( const auto& p : matching_events )\n            {\n                result.message() << p << \"\\n\";\n            }\n\n            BOOST_CHECK( result );\n        }\n    }\n\n    void radio_base::check_outgoing_l2cap_pdu( std::initializer_list< std::uint16_t > pattern )\n    {\n        check_single_event(\n            filter_events( filter_l2cap, connection_events_, pattern ),\n            \"no outgoing l2cap PDU matches the given pattern: \",\n            \"multiple outgoing l2cap PDU matches the given pattern: \",\n            pattern );\n    }\n\n    void radio_base::check_outgoing_ll_control_pdu( std::initializer_list< std::uint16_t > pattern )\n    {\n        check_single_event(\n            filter_events( filter_ll, connection_events_, pattern ),\n            \"no outgoing LL PDU matches the given pattern: \",\n            \"multiple outgoing LL PDU matches the given pattern: \",\n            pattern );\n    }\n\n    void radio_base::clear_events()\n    {\n        advertised_data_.clear();\n        connection_events_.clear();\n    }\n\n    std::uint32_t radio_base::static_random_address_seed() const\n    {\n        return 0x47110815;\n    }\n\n    const bluetoe::link_layer::delta_time radio_base::T_IFS = bluetoe::link_layer::delta_time( 150u );\n\n    void radio_base::end_of_simulation( bluetoe::link_layer::delta_time eos )\n    {\n        eos_ = eos;\n    }\n\n\n    radio_base::lock_guard::lock_guard()\n    {\n        assert( !locked_ );\n        locked_ = true;\n    }\n\n    radio_base::lock_guard::~lock_guard()\n    {\n        locked_ = false;\n    }\n\n    bool radio_base::lock_guard::locked_ = false;\n}\n"
  },
  {
    "path": "tests/test_tools/test_radio.hpp",
    "content": "#ifndef BLUETOE_TESTS_LINK_LAYER_TEST_RADIO_HPP\n#define BLUETOE_TESTS_LINK_LAYER_TEST_RADIO_HPP\n\n#include <bluetoe/buffer.hpp>\n#include <bluetoe/delta_time.hpp>\n#include <bluetoe/ll_data_pdu_buffer.hpp>\n#include <bluetoe/link_layer.hpp>\n#include <bluetoe/connection_events.hpp>\n\n#include <vector>\n#include <functional>\n#include <iosfwd>\n#include <initializer_list>\n#include <iostream>\n\nnamespace test {\n\n    /**\n     * @brief expression that can be used in some of the finder functions to denote that this is always a match\n     */\n    static constexpr std::uint16_t X = 0x0100;\n\n    /**\n     * @brief expresssion that can be used as a last element of an expression to a finder function to denote that\n     *        you do not care about the reset of the pdu.\n     */\n    static constexpr std::uint16_t and_so_on = 0x0200;\n\n    /**\n     * @brief stores all relevant arguments to a schedule_advertisment() function call to the radio\n     */\n    struct advertising_data\n    {\n        bluetoe::link_layer::delta_time     schedule_time;     // when was the actions scheduled (from start of simulation)\n        bluetoe::link_layer::delta_time     on_air_time;       // when was the action on air (from start of simulation)\n\n        // parameters\n        unsigned                            channel;\n        bluetoe::link_layer::delta_time     transmision_time;  // or start of receiving\n        std::vector< std::uint8_t >         transmitted_data;\n        bluetoe::link_layer::read_buffer    receive_buffer;\n\n        std::uint32_t                       access_address;\n        std::uint32_t                       crc_init;\n    };\n\n    std::ostream& operator<<( std::ostream& out, const advertising_data& data );\n    std::ostream& operator<<( std::ostream& out, const std::vector< advertising_data >& data );\n\n    struct pdu_t {\n        std::vector< std::uint8_t > data;\n        bool                        encrypted;\n\n        using iterator       = std::vector< std::uint8_t >::iterator;\n        using const_iterator = std::vector< std::uint8_t >::const_iterator;\n\n        iterator begin()\n        {\n            return data.begin();\n        }\n\n        iterator end()\n        {\n            return data.end();\n        }\n\n        const_iterator begin() const\n        {\n            return data.begin();\n        }\n\n        const_iterator end() const\n        {\n            return data.end();\n        }\n\n        std::size_t size() const\n        {\n            return data.size();\n        }\n\n        std::uint8_t& operator[]( int index )\n        {\n            return data[ index ];\n        }\n\n        std::uint8_t operator[]( int index ) const\n        {\n            return data[ index ];\n        }\n\n        pdu_t( const std::vector< std::uint8_t > d )\n            : data( d )\n            , encrypted( false )\n        {}\n\n        pdu_t( const std::vector< std::uint8_t > d, bool enc )\n            : data( d )\n            , encrypted( enc )\n        {}\n\n        pdu_t( std::initializer_list< std::uint8_t > list )\n            : data( list )\n            , encrypted( false )\n        {}\n    };\n\n    using pdu_list_t = std::vector< pdu_t >;\n\n    std::ostream& operator<<( std::ostream& out, const pdu_t& data );\n    std::ostream& operator<<( std::ostream& out, const pdu_list_t& data );\n    std::ostream& operator<<( std::ostream& out, bluetoe::link_layer::phy_ll_encoding::phy_ll_encoding_t phy );\n\n    struct connection_event\n    {\n        bluetoe::link_layer::delta_time     schedule_time;     // when was the actions scheduled (from start of simulation)\n\n        // parameters\n        unsigned                            channel;\n        bluetoe::link_layer::delta_time     start_receive;\n        bluetoe::link_layer::delta_time     end_receive;\n        bluetoe::link_layer::delta_time     connection_interval;\n\n        bluetoe::link_layer::phy_ll_encoding::phy_ll_encoding_t receiving_encoding;\n        bluetoe::link_layer::phy_ll_encoding::phy_ll_encoding_t transmission_encoding;\n\n        std::uint32_t                       access_address;\n        std::uint32_t                       crc_init;\n\n        pdu_list_t                          transmitted_data;\n        pdu_list_t                          received_data;\n\n        bool                                receive_encryption_at_start_of_event;\n        bool                                transmit_encryption_at_start_of_event;\n    };\n\n    std::ostream& operator<<( std::ostream& out, const connection_event& );\n    std::ostream& operator<<( std::ostream& out, const std::vector< connection_event >& list );\n\n    struct connection_event_response\n    {\n        bool                                timeout; // respond with an timeout\n        pdu_list_t                          data;    // respond with data (including no data)\n        std::function< pdu_list_t () >      func;    // inquire respond by calling func\n\n        /**\n         * @brief simulating no response, not even an empty PDU.\n         */\n        connection_event_response()\n            : timeout( true )\n        {}\n\n        explicit connection_event_response( const pdu_list_t& d )\n            : timeout( false )\n            , data( d )\n        {}\n\n        explicit connection_event_response( const std::function< pdu_list_t () >& f )\n            : timeout( false )\n            , func( f )\n        {}\n\n        explicit connection_event_response( const std::function< void() >& f )\n            : timeout( false )\n            , func( [f](){ f(); return pdu_list_t(); } )\n        {}\n    };\n\n    std::ostream& operator<<( std::ostream& out, const connection_event_response& );\n\n    struct advertising_response\n    {\n        advertising_response();\n\n        advertising_response( unsigned c, std::vector< std::uint8_t > d, const bluetoe::link_layer::delta_time l );\n\n        static advertising_response crc_error();\n\n        unsigned                        channel;\n        std::vector< std::uint8_t >     received_data;\n        bluetoe::link_layer::delta_time delay;\n        bool                            has_crc_error;\n    };\n\n    std::ostream& operator<<( std::ostream& out, const advertising_response& data );\n\n    struct scheduled_user_timer\n    {\n        bluetoe::link_layer::delta_time     schedule_time;      // when was the actions scheduled (from start of simulation)\n        bluetoe::link_layer::delta_time     current_anchor;     // Anchor on which delay is based\n        bluetoe::link_layer::delta_time     delay;\n    };\n\n    std::ostream& operator<<( std::ostream& out, const scheduled_user_timer& data );\n    std::ostream& operator<<( std::ostream& out, const std::vector< scheduled_user_timer >& data );\n\n    /**\n     * @brief returns true, if pdu matches pattern.\n     * @sa X\n     * @sa and_so_on\n     */\n    bool check_pdu( const pdu_t& pdu, std::initializer_list< std::uint16_t > pattern );\n\n    /**\n     * @brief prints a pattern, so that it's easy comparable to a PDU\n     */\n    std::string pretty_print_pattern( std::initializer_list< std::uint16_t > pattern );\n\n    class radio_base\n    {\n    public:\n        radio_base();\n\n        // test interface\n        const std::vector< advertising_data >& advertisings() const;\n        const std::vector< connection_event >& connection_events() const;\n        const std::vector< scheduled_user_timer >& scheduled_user_timers() const;\n\n        /**\n         * @brief calls check with every scheduled_data\n         */\n        void check_scheduling( const std::function< bool ( const advertising_data& ) >& check, const char* message ) const;\n\n        /**\n         * @brief calls check with adjanced pairs of advertising_data.\n         */\n        void check_scheduling( const std::function< bool ( const advertising_data& first, const advertising_data& next ) >& check, const char* message ) const;\n        void check_scheduling( const std::function< bool ( const advertising_data& ) >& filter, const std::function< bool ( const advertising_data& first, const advertising_data& next ) >& check, const char* message ) const;\n        void check_scheduling( const std::function< bool ( const advertising_data& ) >& filter, const std::function< bool ( const advertising_data& data ) >& check, const char* message ) const;\n\n        void check_first_scheduling( const std::function< bool ( const advertising_data& ) >& filter, const std::function< bool ( const advertising_data& data ) >& check, const char* message ) const;\n\n        /**\n         * @brief there must be exactly one scheduled_data that fitts to the given filter\n         */\n        void find_scheduling( const std::function< bool ( const advertising_data& ) >& filter, const char* message ) const;\n        void find_scheduling( const std::function< bool ( const advertising_data& first, const advertising_data& next ) >& check, const char* message ) const;\n\n        void all_data( std::function< void ( const advertising_data& ) > ) const;\n        void all_data( const std::function< bool ( const advertising_data& ) >& filter, const std::function< void ( const advertising_data& first, const advertising_data& next ) >& ) const;\n\n        template < class Accu >\n        Accu sum_data( std::function< Accu ( const advertising_data&, Accu start_value ) >, Accu start_value ) const;\n\n        /**\n         * @brief counts the number of times the given filter returns true for all advertising_data\n         */\n        unsigned count_data( const std::function< bool ( const advertising_data& ) >& filter ) const;\n\n        /**\n         * @brief function to take the arguments to a scheduling function and optional return a response\n         */\n        typedef std::function< std::pair< bool, advertising_response > ( const advertising_data& ) > advertising_responder_t;\n\n        /**\n         * @brief simulates an incomming PDU\n         *\n         * Given that a transmition was scheduled and the function responder() returns a pair with the first bool set to true, when applied to the transmitting\n         * data, the given advertising_response is used to simulate an incoming PDU. The first function that returns true, will be applied and removed from the list.\n         */\n        void add_responder( const advertising_responder_t& responder );\n\n        /**\n         * @brief response to sending on the given channel with the given PDU send on the same channel without delay\n         */\n        void respond_to( unsigned channel, std::initializer_list< std::uint8_t > pdu );\n        void respond_to( unsigned channel, std::vector< std::uint8_t > pdu );\n        void respond_with_crc_error( unsigned channel );\n\n        /**\n         * @brief response `times` times\n         */\n        void respond_to( unsigned channel, std::initializer_list< std::uint8_t > pdu, unsigned times );\n\n        void set_access_address_and_crc_init( std::uint32_t access_address, std::uint32_t crc_init );\n\n        std::uint32_t access_address() const;\n        std::uint32_t crc_init() const;\n\n        void add_connection_event_respond( const connection_event_response& );\n        void add_connection_event_respond( std::initializer_list< std::uint8_t > );\n        void add_connection_event_respond( std::function< void() > );\n        void add_connection_event_respond_timeout();\n\n        void check_connection_events( const std::function< bool ( const connection_event& ) >& filter, const std::function< bool ( const connection_event& ) >& check, const char* message );\n        void check_connection_events( const std::function< bool ( const connection_event& ) >& check, const char* message );\n\n        /**\n         * @brief check that exacly one outgoing l2cap layer pdu matches the given pattern\n         */\n        void check_outgoing_l2cap_pdu( std::initializer_list< std::uint16_t > pattern );\n\n        /**\n         * @brief check that exacly one outgoing link layer pdu matches the given pattern\n         */\n        void check_outgoing_ll_control_pdu( std::initializer_list< std::uint16_t > pattern );\n\n        /**\n         * @brief clear all events\n         */\n        void clear_events();\n\n        /**\n         * @brief returns 0x47110815\n         */\n        std::uint32_t static_random_address_seed() const;\n\n        static const bluetoe::link_layer::delta_time T_IFS;\n\n        void end_of_simulation( bluetoe::link_layer::delta_time );\n\n        class lock_guard\n        {\n        public:\n            lock_guard();\n            ~lock_guard();\n\n            lock_guard( const lock_guard& ) = delete;\n            lock_guard& operator=( const lock_guard& ) = delete;\n        private:\n            static bool locked_;\n        };\n\n        static constexpr std::size_t radio_maximum_white_list_entries = 0;\n\n        void increment_receive_packet_counter() {}\n        void increment_transmit_packet_counter() {}\n\n        void radio_set_phy(\n            bluetoe::link_layer::phy_ll_encoding::phy_ll_encoding_t receiving_encoding,\n            bluetoe::link_layer::phy_ll_encoding::phy_ll_encoding_t transmiting_c_encoding );\n\n    protected:\n        typedef std::vector< advertising_data > advertising_list;\n        advertising_list advertised_data_;\n\n        typedef std::vector< connection_event > connection_event_list;\n        connection_event_list connection_events_;\n\n        typedef std::vector< advertising_responder_t > responder_list;\n        responder_list responders_;\n\n        typedef std::vector< connection_event_response > connection_event_response_list;\n        connection_event_response_list connection_events_response_;\n\n        typedef std::vector< scheduled_user_timer > scheduled_user_timers_list;\n        scheduled_user_timers_list scheduled_user_timers_;\n\n        std::uint32_t   access_address_;\n        std::uint32_t   crc_init_;\n        bool            access_address_and_crc_valid_;\n        std::uint8_t    central_sequence_number_    = 0;\n        std::uint8_t    central_ne_sequence_number_ = 0;\n\n        bluetoe::link_layer::phy_ll_encoding::phy_ll_encoding_t    receiving_encoding_;\n        bluetoe::link_layer::phy_ll_encoding::phy_ll_encoding_t    transmiting_encoding_;\n\n        static constexpr std::size_t ll_header_size = 2;\n\n        // end of simulations\n        bluetoe::link_layer::delta_time eos_;\n\n        advertising_list::const_iterator next( std::vector< advertising_data >::const_iterator, const std::function< bool ( const advertising_data& ) >& filter ) const;\n\n        void pair_wise_check(\n            const std::function< bool ( const advertising_data& ) >&                                               filter,\n            const std::function< bool ( const advertising_data& first, const advertising_data& next ) >&              check,\n            const std::function< void ( advertising_list::const_iterator first, advertising_list::const_iterator next ) >&    fail ) const;\n\n        std::pair< bool, advertising_response > find_response( const advertising_data& );\n    };\n\n    /**\n     * @brief test implementation of the link_layer::scheduled_radio interface, that simulates receiving and transmitted data\n     */\n    template < std::size_t TransmitSize, std::size_t ReceiveSize, typename CallBack,\n        bool Phy2MBitSupported,\n        bool SynchronizedUserTimerSupported >\n    class radio_impl :\n        public radio_base,\n        public bluetoe::link_layer::ll_data_pdu_buffer<\n            TransmitSize, ReceiveSize,\n            radio_impl<\n                TransmitSize, ReceiveSize, CallBack, Phy2MBitSupported, SynchronizedUserTimerSupported\n            >\n        >\n    {\n    public:\n        /**\n         * @brief by default the radio simulates 10s without any response\n         */\n        radio_impl();\n\n        // scheduled_radio interface\n        void schedule_advertisment(\n            unsigned                                    channel,\n            const bluetoe::link_layer::write_buffer&    advertising_data,\n            const bluetoe::link_layer::write_buffer&    response_data,\n            bluetoe::link_layer::delta_time             when,\n            const bluetoe::link_layer::read_buffer&     receive );\n\n        bluetoe::link_layer::delta_time schedule_connection_event(\n            unsigned                                    channel,\n            bluetoe::link_layer::delta_time             start_receive,\n            bluetoe::link_layer::delta_time             end_receive,\n            bluetoe::link_layer::delta_time             connection_interval );\n\n        std::pair< bool, bluetoe::link_layer::delta_time > disarm_connection_event();\n\n        bool schedule_synchronized_user_timer(\n            bluetoe::link_layer::delta_time timeout, bluetoe::link_layer::delta_time runtime );\n        bool cancel_synchronized_user_timer();\n\n        void wake_up();\n\n        void request_event_cancelation();\n\n        /**\n         * @brief runs the simulation\n         */\n        void run();\n\n        bool event_cancelation_requested();\n\n        static constexpr bool hardware_supports_encryption = false;\n\n        /**\n         * @brief indicates support for 2Mbit\n         */\n        static constexpr bool hardware_supports_2mbit = Phy2MBitSupported;\n\n        /**\n         * @brief indicates support for schedule_synchronized_user_timer()\n         */\n        static constexpr bool hardware_supports_synchronized_user_timer = SynchronizedUserTimerSupported;\n\n        static constexpr unsigned connection_event_setup_time_us = 100u;\n\n    private:\n        // converts from in memory layout to over the air layout\n        void copy_memory_to_air( const std::vector< std::uint8_t >& in_memory, bluetoe::link_layer::read_buffer& over_the_air );\n        void copy_air_to_memory( const std::vector< std::uint8_t >& over_the_air, bluetoe::link_layer::read_buffer& in_memory );\n\n        // converts from over the air layout to in memory layout\n        std::vector< std::uint8_t > air_to_memory( bluetoe::link_layer::write_buffer );\n        std::vector< std::uint8_t > memory_to_air( bluetoe::link_layer::write_buffer );\n\n        bluetoe::link_layer::delta_time now_;\n        bluetoe::link_layer::delta_time last_anchor_;\n\n        void simulate_advertising_response();\n        void simulate_connection_event_response();\n        bluetoe::link_layer::delta_time simulate_user_timer_response( bluetoe::link_layer::delta_time start, bluetoe::link_layer::delta_time end );\n\n        // make sure, there is only one action scheduled\n        bool idle_;\n        bool advertising_response_;\n        bool connection_event_response_;\n        bool request_event_cancelation_;\n        int  wake_ups_;\n        bool timer_set_;\n\n        // to be set to true, if a connection event was simulated, set back to false, when\n        // use callback get called.\n        bool user_timer_anchor_moved_;\n\n    protected:\n        bool reception_encrypted_;\n        bool transmition_encrypted_;\n    };\n\n    template < std::size_t TransmitSize, std::size_t ReceiveSize, typename CallBack >\n    using radio = radio_impl< TransmitSize, ReceiveSize, CallBack, false, false >;\n\n    template < std::size_t TransmitSize, std::size_t ReceiveSize, typename CallBack >\n    using radio_no_2mbit = radio_impl< TransmitSize, ReceiveSize, CallBack, false, false >;\n\n    template < std::size_t TransmitSize, std::size_t ReceiveSize, typename CallBack >\n    using radio_with_2mbit = radio_impl< TransmitSize, ReceiveSize, CallBack, true, false >;\n\n    template < std::size_t TransmitSize, std::size_t ReceiveSize, typename CallBack >\n    using radio_with_user_timer = radio_impl< TransmitSize, ReceiveSize, CallBack, false, true >;\n\n    template < std::size_t TransmitSize, std::size_t ReceiveSize, typename CallBack >\n    using radio_without_user_timer = radio_impl< TransmitSize, ReceiveSize, CallBack, false, false >;\n\n    /*\n     * The test radio uses a layout that requires more memory\n     *\n     * Use this buffer size during tests as default.\n     */\n    using buffer_sizes = bluetoe::link_layer::buffer_sizes< 61u, 61u >;\n\n    template < std::size_t TransmitSize, std::size_t ReceiveSize, typename CallBack >\n    class radio_with_encryption : public radio< TransmitSize, ReceiveSize, CallBack >\n    {\n    public:\n        static constexpr bool hardware_supports_encryption = true;\n\n        radio_with_encryption()\n            : key_( { { 0x00 } } )\n            , skdm_( 0u )\n            , ivm_( 0u )\n            , skds_( 0x3fac22107855aa56ul )\n            , ivs_( 0x78563412 )\n        {\n        }\n\n        // Security functions\n        bluetoe::details::uint128_t create_srand()\n        {\n            const bluetoe::details::uint128_t r{{\n                0xE0, 0x2E, 0x70, 0xC6,\n                0x4E, 0x27, 0x88, 0x63,\n                0x0E, 0x6F, 0xAD, 0x56,\n                0x21, 0xD5, 0x83, 0x57\n            }};\n\n            return r;\n        }\n\n        bluetoe::details::uint128_t c1(\n            const bluetoe::details::uint128_t& temp_key,\n            const bluetoe::details::uint128_t& /* srand */,\n            const bluetoe::details::uint128_t& /* p1 */,\n            const bluetoe::details::uint128_t& /* p2 */ ) const\n        {\n            return temp_key;\n        }\n\n        bluetoe::details::uint128_t s1(\n            const bluetoe::details::uint128_t& stk,\n            const bluetoe::details::uint128_t& /* srand */,\n            const bluetoe::details::uint128_t& /* mrand */)\n        {\n            return stk;\n        }\n\n        void setup_encryption_response( std::uint64_t SKDs, std::uint32_t IVs)\n        {\n            skds_ = SKDs;\n            ivs_  = IVs;\n        }\n\n        std::pair< std::uint64_t, std::uint32_t > setup_encryption( bluetoe::details::uint128_t k, std::uint64_t skdm, std::uint32_t ivm )\n        {\n            skdm_ = skdm;\n            ivm_  = ivm;\n\n            key_ = k;\n\n            return { skds_, ivs_ };\n        }\n\n        void start_receive_encrypted()\n        {\n            this->reception_encrypted_ = true;\n        }\n\n        void start_transmit_encrypted()\n        {\n            this->transmition_encrypted_ = true;\n        }\n\n        void stop_receive_encrypted()\n        {\n            this->reception_encrypted_ = false;\n        }\n\n        void stop_transmit_encrypted()\n        {\n            this->transmition_encrypted_ = false;\n        }\n\n        // access to data provided for testing\n        bluetoe::details::uint128_t encryption_key() const\n        {\n            return key_;\n        }\n\n        std::uint64_t skdm() const\n        {\n            return skdm_;\n        }\n\n        std::uint32_t ivm() const\n        {\n            return ivm_;\n        }\n\n    private:\n        bluetoe::details::uint128_t key_;\n        std::uint64_t               skdm_;\n        std::uint32_t               ivm_;\n        std::uint64_t               skds_;\n        std::uint32_t               ivs_;\n    };\n\n    // implementation\n    template < class Accu >\n    Accu radio_base::sum_data( std::function< Accu ( const advertising_data&, Accu start_value ) > f, Accu start_value ) const\n    {\n        for ( const auto& d : advertised_data_ )\n            start_value = f( d, start_value );\n\n        return start_value;\n    }\n\n    template < std::size_t TransmitSize, std::size_t ReceiveSize, typename CallBack, bool Phy2MBitSupported, bool SynchronizedUserTimerSupported >\n    radio_impl< TransmitSize, ReceiveSize, CallBack, Phy2MBitSupported, SynchronizedUserTimerSupported >::radio_impl()\n        : now_( bluetoe::link_layer::delta_time::now() )\n        , last_anchor_( bluetoe::link_layer::delta_time::now() )\n        , idle_( true )\n        , advertising_response_( false )\n        , connection_event_response_( false )\n        , request_event_cancelation_( false )\n        , wake_ups_( 0 )\n        , timer_set_( false )\n        , user_timer_anchor_moved_( false )\n        , reception_encrypted_( false )\n        , transmition_encrypted_( false )\n    {\n    }\n\n    template < std::size_t TransmitSize, std::size_t ReceiveSize, typename CallBack, bool Phy2MBitSupported, bool SynchronizedUserTimerSupported >\n    void radio_impl< TransmitSize, ReceiveSize, CallBack, Phy2MBitSupported, SynchronizedUserTimerSupported >::schedule_advertisment(\n            unsigned                                    channel,\n            const bluetoe::link_layer::write_buffer&    transmit,\n            const bluetoe::link_layer::write_buffer&,\n            bluetoe::link_layer::delta_time             when,\n            const bluetoe::link_layer::read_buffer&     receive )\n    {\n        assert( idle_ );\n        assert( access_address_and_crc_valid_ );\n        assert( transmit.buffer );\n\n        idle_ = false;\n        advertising_response_ = true;\n        connection_event_response_ = false;\n\n        const advertising_data data{\n            now_,\n            now_ + when,\n            channel,\n            when,\n            memory_to_air( transmit ),\n            receive,\n            access_address_,\n            crc_init_\n        };\n\n        advertised_data_.push_back( data );\n    }\n\n    template < std::size_t TransmitSize, std::size_t ReceiveSize, typename CallBack, bool Phy2MBitSupported, bool SynchronizedUserTimerSupported >\n    bluetoe::link_layer::delta_time radio_impl< TransmitSize, ReceiveSize, CallBack, Phy2MBitSupported, SynchronizedUserTimerSupported >::schedule_connection_event(\n        unsigned                                    channel,\n        bluetoe::link_layer::delta_time             start_receive,\n        bluetoe::link_layer::delta_time             end_receive,\n        bluetoe::link_layer::delta_time             connection_interval )\n    {\n        advertising_response_ = false;\n        connection_event_response_ = true;\n\n        const connection_event data{\n            now_,\n            channel,\n            start_receive,\n            end_receive,\n            connection_interval,\n            receiving_encoding_,\n            transmiting_encoding_,\n            access_address_,\n            crc_init_,\n            pdu_list_t(),\n            pdu_list_t(),\n            reception_encrypted_,\n            transmition_encrypted_\n        };\n\n        connection_events_.push_back( data );\n\n        return bluetoe::link_layer::delta_time();\n    }\n\n    template < std::size_t TransmitSize, std::size_t ReceiveSize, typename CallBack, bool Phy2MBitSupported, bool SynchronizedUserTimerSupported >\n    std::pair< bool, bluetoe::link_layer::delta_time > radio_impl< TransmitSize, ReceiveSize, CallBack, Phy2MBitSupported, SynchronizedUserTimerSupported >::disarm_connection_event()\n    {\n        assert( !connection_events_.empty() );\n        connection_events_.pop_back();\n\n        return { true, bluetoe::link_layer::delta_time() };\n    }\n\n    template < std::size_t TransmitSize, std::size_t ReceiveSize, typename CallBack, bool Phy2MBitSupported, bool SynchronizedUserTimerSupported >\n    bool radio_impl< TransmitSize, ReceiveSize, CallBack, Phy2MBitSupported, SynchronizedUserTimerSupported >::schedule_synchronized_user_timer(\n        bluetoe::link_layer::delta_time time, bluetoe::link_layer::delta_time )\n    {\n        assert( !timer_set_ );\n\n        user_timer_anchor_moved_ = false;\n\n        const scheduled_user_timer new_timer = { now_, last_anchor_, time };\n        scheduled_user_timers_.push_back( new_timer );\n\n        timer_set_ = true;\n\n        return true;\n    }\n\n    template < std::size_t TransmitSize, std::size_t ReceiveSize, typename CallBack, bool Phy2MBitSupported, bool SynchronizedUserTimerSupported >\n    bool radio_impl< TransmitSize, ReceiveSize, CallBack, Phy2MBitSupported, SynchronizedUserTimerSupported >::cancel_synchronized_user_timer()\n    {\n        const bool result = timer_set_;\n\n        if ( timer_set_ )\n        {\n            timer_set_ = false;\n            scheduled_user_timers_.pop_back();\n        }\n\n        return result;\n    }\n\n    template < std::size_t TransmitSize, std::size_t ReceiveSize, typename CallBack, bool Phy2MBitSupported, bool SynchronizedUserTimerSupported >\n    void radio_impl< TransmitSize, ReceiveSize, CallBack, Phy2MBitSupported, SynchronizedUserTimerSupported >::wake_up()\n    {\n        ++wake_ups_;\n    }\n\n    template < std::size_t TransmitSize, std::size_t ReceiveSize, typename CallBack, bool Phy2MBitSupported, bool SynchronizedUserTimerSupported >\n    void radio_impl< TransmitSize, ReceiveSize, CallBack, Phy2MBitSupported, SynchronizedUserTimerSupported >::request_event_cancelation()\n    {\n        request_event_cancelation_ = true;\n    }\n\n    template < std::size_t TransmitSize, std::size_t ReceiveSize, typename CallBack, bool Phy2MBitSupported, bool SynchronizedUserTimerSupported >\n    bool radio_impl< TransmitSize, ReceiveSize, CallBack, Phy2MBitSupported, SynchronizedUserTimerSupported >::event_cancelation_requested()\n    {\n        const bool result = request_event_cancelation_;\n        request_event_cancelation_ = false;\n\n        return result;\n    }\n\n    template < std::size_t TransmitSize, std::size_t ReceiveSize, typename CallBack, bool Phy2MBitSupported, bool SynchronizedUserTimerSupported >\n    void radio_impl< TransmitSize, ReceiveSize, CallBack, Phy2MBitSupported, SynchronizedUserTimerSupported >::run()\n    {\n        bool new_scheduling_added = false;\n        central_sequence_number_    = 0;\n        central_ne_sequence_number_ = 0;\n\n        do\n        {\n            unsigned count = advertised_data_.size() + connection_events_.size();\n\n            if ( advertising_response_ )\n            {\n                advertising_response_ = false;\n                simulate_advertising_response();\n            }\n            else if ( connection_event_response_ )\n            {\n                connection_event_response_ = false;\n                simulate_connection_event_response();\n            }\n\n            // there should be at max one call to a schedule function\n            assert( count + 1 >= advertised_data_.size() + connection_events_.size() );\n\n            new_scheduling_added = advertised_data_.size() + connection_events_.size() > count;\n        } while ( now_ < eos_ && new_scheduling_added && wake_ups_ == 0 );\n\n        if ( wake_ups_ )\n            --wake_ups_;\n    }\n\n    template < std::size_t TransmitSize, std::size_t ReceiveSize, typename CallBack, bool Phy2MBitSupported, bool SynchronizedUserTimerSupported >\n    void radio_impl< TransmitSize, ReceiveSize, CallBack, Phy2MBitSupported, SynchronizedUserTimerSupported >::simulate_advertising_response()\n    {\n        assert( !advertised_data_.empty() );\n\n        advertising_data&                       current  = advertised_data_.back();\n        std::pair< bool, advertising_response > response = find_response( current );\n\n        if ( response.first )\n        {\n            now_ += T_IFS;\n\n            if ( response.second.has_crc_error )\n            {\n                idle_ = true;\n                static_cast< CallBack* >( this )->adv_timeout();\n            }\n            else\n            {\n                if ( current.receive_buffer.size > 0 )\n                    copy_air_to_memory( response.second.received_data, current.receive_buffer );\n\n                idle_ = true;\n                static_cast< CallBack* >( this )->adv_received( current.receive_buffer );\n            }\n        }\n        else\n        {\n            now_ += advertised_data_.back().transmision_time;\n            idle_ = true;\n            static_cast< CallBack* >( this )->adv_timeout();\n        }\n    }\n\n    template < std::size_t TransmitSize, std::size_t ReceiveSize, typename CallBack, bool Phy2MBitSupported, bool SynchronizedUserTimerSupported >\n    void radio_impl< TransmitSize, ReceiveSize, CallBack, Phy2MBitSupported, SynchronizedUserTimerSupported >::simulate_connection_event_response()\n    {\n        using layout = typename bluetoe::link_layer::pdu_layout_by_radio< radio_impl< TransmitSize, ReceiveSize, CallBack, Phy2MBitSupported, SynchronizedUserTimerSupported > >::pdu_layout;\n\n        connection_event_response response = connection_events_response_.empty()\n            ? connection_event_response()\n            : connection_events_response_.front();\n\n        assert( !connection_events_.empty() );\n        auto& event = connection_events_.back();\n\n        if ( !connection_events_response_.empty() )\n        {\n            connection_events_response_.erase( connection_events_response_.begin() );\n        }\n\n        if ( response.timeout )\n        {\n            now_ = simulate_user_timer_response( now_, now_ + event.end_receive );\n            static_cast< CallBack* >( this )->timeout();\n        }\n        else\n        {\n            last_anchor_ = now_;\n            now_ = simulate_user_timer_response( now_, now_ + event.start_receive );\n            user_timer_anchor_moved_ = true;\n\n            static constexpr std::uint8_t sn_flag        = 0x8;\n            static constexpr std::uint8_t nesn_flag      = 0x4;\n            static constexpr std::uint8_t more_data_flag = 0x10;\n\n            bool more_data = false;\n\n            pdu_list_t pdus = response.data;\n\n            if ( pdus.empty() && response.func )\n                pdus = response.func();\n\n            bluetoe::link_layer::connection_event_events events;\n\n            do\n            {\n                auto receive_buffer = this->allocate_receive_buffer();\n\n                more_data = false;\n\n                if ( receive_buffer.size )\n                {\n                    // what is the link layer going to receive?\n                    if ( pdus.empty() )\n                    {\n                        layout::header( receive_buffer.buffer, 0x0001 );\n                    }\n                    else\n                    {\n                        const auto pdu = pdus.front();\n                        pdus.erase( pdus.begin() );\n\n                        copy_air_to_memory( pdu.data, receive_buffer );\n\n                        more_data = !pdus.empty();\n                    }\n\n                    std::uint16_t header = layout::header( receive_buffer );\n                    header &= ~( sn_flag | nesn_flag );\n                    header |= central_sequence_number_ | central_ne_sequence_number_;\n                    layout::header( receive_buffer, header );\n\n                    central_sequence_number_    ^= sn_flag;\n                }\n\n                if ( more_data && receive_buffer.size )\n                {\n                    const std::uint16_t header = layout::header( receive_buffer ) | more_data_flag;\n                    layout::header( receive_buffer, header );\n                }\n\n                auto response = this->received( receive_buffer );\n\n                more_data = more_data || ( layout::header( response ) & more_data_flag );\n                central_ne_sequence_number_ ^= nesn_flag;\n\n                event.received_data.push_back(\n                    memory_to_air( bluetoe::link_layer::write_buffer( receive_buffer ) ) );\n\n                event.transmitted_data.push_back(\n                    pdu_t( memory_to_air( response ), transmition_encrypted_ ) );\n\n            } while ( more_data );\n\n            static_cast< CallBack* >( this )->end_event( events );\n        }\n    }\n\n    template < std::size_t TransmitSize, std::size_t ReceiveSize, typename CallBack, bool Phy2MBitSupported, bool SynchronizedUserTimerSupported >\n    bluetoe::link_layer::delta_time radio_impl< TransmitSize, ReceiveSize, CallBack, Phy2MBitSupported, SynchronizedUserTimerSupported >::simulate_user_timer_response( bluetoe::link_layer::delta_time /* start */, bluetoe::link_layer::delta_time end )\n    {\n        while ( timer_set_ && !scheduled_user_timers_.empty() && scheduled_user_timers_.back().current_anchor + scheduled_user_timers_.back().delay < end )\n        {\n            now_ = scheduled_user_timers_.back().current_anchor + scheduled_user_timers_.back().delay;\n\n            timer_set_ = false;\n            const bool anchor = user_timer_anchor_moved_;\n            user_timer_anchor_moved_ = false;\n            static_cast< CallBack* >( this )->user_timer( anchor );\n        }\n\n        return end;\n    }\n\n    template < std::size_t TransmitSize, std::size_t ReceiveSize, typename CallBack, bool Phy2MBitSupported, bool SynchronizedUserTimerSupported >\n    void radio_impl< TransmitSize, ReceiveSize, CallBack, Phy2MBitSupported, SynchronizedUserTimerSupported >::copy_memory_to_air( const std::vector< std::uint8_t >& in_memory, bluetoe::link_layer::read_buffer& over_the_air )\n    {\n        using layout = typename bluetoe::link_layer::pdu_layout_by_radio< radio_impl< TransmitSize, ReceiveSize, CallBack, Phy2MBitSupported, SynchronizedUserTimerSupported > >::pdu_layout;\n\n        const auto          body      = layout::body( bluetoe::link_layer::write_buffer( in_memory.data(), in_memory.size() ) );\n        const std::uint16_t header    = layout::header( in_memory.data() );\n        const std::size_t   body_size = std::min< std::size_t >( over_the_air.size - ll_header_size, std::distance( body.first, body.second ) );\n\n        bluetoe::details::write_16bit( over_the_air.buffer, header );\n        std::copy( body.first, body.first + body_size, over_the_air.buffer + ll_header_size );\n\n        over_the_air.size = body_size + ll_header_size;\n    }\n\n    template < std::size_t TransmitSize, std::size_t ReceiveSize, typename CallBack, bool Phy2MBitSupported, bool SynchronizedUserTimerSupported >\n    void radio_impl< TransmitSize, ReceiveSize, CallBack, Phy2MBitSupported, SynchronizedUserTimerSupported >::copy_air_to_memory( const std::vector< std::uint8_t >& over_the_air, bluetoe::link_layer::read_buffer& in_memory )\n    {\n        using layout = typename bluetoe::link_layer::pdu_layout_by_radio< radio_impl< TransmitSize, ReceiveSize, CallBack, Phy2MBitSupported, SynchronizedUserTimerSupported > >::pdu_layout;\n\n        const std::uint16_t header = bluetoe::details::read_16bit( over_the_air.data() );\n        const std::size_t   size   = std::min< std::size_t >( header >> 8, over_the_air.size() - ll_header_size );\n        const auto          body   = layout::body( in_memory );\n\n        layout::header( in_memory, header );\n        std::copy( over_the_air.data() + ll_header_size, over_the_air.data() + ll_header_size + size, body.first );\n\n        in_memory.size = layout::data_channel_pdu_memory_size( size );\n    }\n\n    template < std::size_t TransmitSize, std::size_t ReceiveSize, typename CallBack, bool Phy2MBitSupported, bool SynchronizedUserTimerSupported >\n    std::vector< std::uint8_t > radio_impl< TransmitSize, ReceiveSize, CallBack, Phy2MBitSupported, SynchronizedUserTimerSupported >::air_to_memory( bluetoe::link_layer::write_buffer air )\n    {\n        using layout = typename bluetoe::link_layer::pdu_layout_by_radio< radio_impl< TransmitSize, ReceiveSize, CallBack, Phy2MBitSupported, SynchronizedUserTimerSupported > >::pdu_layout;\n\n        const std::uint16_t header = bluetoe::details::read_16bit( air.buffer );\n        const std::size_t   size   = header >> 8;\n\n        std::vector< std::uint8_t > result( layout::data_channel_pdu_memory_size( size ) );\n\n        const auto          body   = layout::body( bluetoe::link_layer::read_buffer{ &result[ 0 ], result.size() } );\n\n        layout::header( &result[ 0 ], header );\n        std::copy( air.buffer + ll_header_size, air.buffer + ll_header_size + size, body.first );\n\n        return result;\n    }\n\n    template < std::size_t TransmitSize, std::size_t ReceiveSize, typename CallBack, bool Phy2MBitSupported, bool SynchronizedUserTimerSupported >\n    std::vector< std::uint8_t > radio_impl< TransmitSize, ReceiveSize, CallBack, Phy2MBitSupported, SynchronizedUserTimerSupported >::memory_to_air( bluetoe::link_layer::write_buffer memory )\n    {\n        using layout = typename bluetoe::link_layer::pdu_layout_by_radio< radio_impl< TransmitSize, ReceiveSize, CallBack, Phy2MBitSupported, SynchronizedUserTimerSupported > >::pdu_layout;\n\n        const std::uint16_t header    = layout::header( memory );\n        const auto          body      = layout::body( memory );\n        const std::size_t   body_size = header >> 8;\n\n        std::vector< std::uint8_t > air( body_size + ll_header_size );\n        bluetoe::details::write_16bit( &air[ 0 ], header );\n        std::copy( body.first, body.first + body_size, &air[ ll_header_size ] );\n\n        return air;\n    }\n\n    struct pdu_layout : bluetoe::link_layer::details::layout_base< pdu_layout > {\n        static constexpr std::size_t header_size = sizeof( std::uint16_t );\n\n        using bluetoe::link_layer::details::layout_base< pdu_layout >::header;\n\n        static std::uint16_t header( const std::uint8_t* pdu )\n        {\n            return ::bluetoe::details::read_16bit( pdu ) ^ 0xffff;\n        }\n\n        static void header( std::uint8_t* pdu, std::uint16_t header_value )\n        {\n            ::bluetoe::details::write_16bit( pdu, header_value ^ 0xffff );\n        }\n\n        static std::pair< std::uint8_t*, std::uint8_t* > body( const bluetoe::link_layer::read_buffer& pdu )\n        {\n            assert( pdu.size >= header_size );\n\n            return { &pdu.buffer[ header_size + 2 ], &pdu.buffer[ pdu.size ] };\n        }\n\n        static std::pair< const std::uint8_t*, const std::uint8_t* > body( const bluetoe::link_layer::write_buffer& pdu )\n        {\n            assert( pdu.size >= header_size );\n\n            return { &pdu.buffer[ header_size + 2 ], &pdu.buffer[ pdu.size ] };\n        }\n\n        static constexpr std::size_t data_channel_pdu_memory_size( std::size_t payload_size )\n        {\n            return header_size + payload_size + 2;\n        }\n    };\n\n}\n\n/*\n * To make sure, that all parts of the library take the PDU layout into account, all tests are done\n * with a special layout, where the header is inverted and where a gap (of 2 octets) between header and octets is inserted.\n */\nnamespace bluetoe {\n    namespace link_layer {\n\n        template < std::size_t TransmitSize, std::size_t ReceiveSize, typename CallBack >\n        struct pdu_layout_by_radio< test::radio< TransmitSize, ReceiveSize, CallBack > >\n        {\n            using pdu_layout = test::pdu_layout;\n        };\n\n        template < std::size_t TransmitSize, std::size_t ReceiveSize, typename CallBack >\n        struct pdu_layout_by_radio< test::radio_with_encryption< TransmitSize, ReceiveSize, CallBack > >\n        {\n            using pdu_layout = test::pdu_layout;\n        };\n   }\n}\n\n#endif // include guard\n"
  },
  {
    "path": "tests/test_tools/test_servers.cpp",
    "content": "#include <cstdint>\n\nnamespace test {\n    std::uint16_t temperature_value = 0x0104;\n\n    std::uint8_t ape1 = 1;\n    std::uint8_t ape2 = 2;\n    std::uint8_t ape3 = 3;\n}\n"
  },
  {
    "path": "tests/test_tools/test_servers.hpp",
    "content": "#ifndef BLUETOE_TESTS_TEST_SERVERS_HPP\n#define BLUETOE_TESTS_TEST_SERVERS_HPP\n\n#include <bluetoe/server.hpp>\n#include <bluetoe/service.hpp>\n#include <bluetoe/characteristic.hpp>\n#include <bluetoe/gatt_options.hpp>\n\n#include <initializer_list>\n#include <vector>\n#include <sstream>\n#include <iostream>\n#include <iomanip>\n#include <iterator>\n#include <set>\n\n#include \"hexdump.hpp\"\n\nnamespace test {\n    extern std::uint16_t temperature_value;\n\n    typedef bluetoe::server<\n        bluetoe::service<\n            bluetoe::service_uuid< 0x8C8B4094, 0x0DE2, 0x499F, 0xA28A, 0x4EED5BC73CA9 >,\n            bluetoe::characteristic<\n                bluetoe::characteristic_uuid< 0x8C8B4094, 0x0DE2, 0x499F, 0xA28A, 0x4EED5BC73CAA >,\n                bluetoe::bind_characteristic_value< decltype( temperature_value ), &temperature_value >,\n                bluetoe::no_write_access\n            >\n        >,\n        bluetoe::no_gap_service_for_gatt_servers\n    > small_temperature_service;\n\n    /*\n     * Example with 3 characteristics, the example contains 7 attributes.\n     */\n    extern std::uint8_t ape1;\n    extern std::uint8_t ape2;\n    extern std::uint8_t ape3;\n\n    typedef bluetoe::server<\n        bluetoe::service<\n            bluetoe::service_uuid< 0x8C8B4094, 0x0DE2, 0x499F, 0xA28A, 0x4EED5BC73CA9 >,\n            bluetoe::characteristic<\n                bluetoe::characteristic_uuid< 0x8C8B4094, 0x0DE2, 0x499F, 0xA28A, 0x4EED5BC73CAA >,\n                bluetoe::bind_characteristic_value< std::uint8_t, &ape1 >\n            >,\n            bluetoe::characteristic<\n                bluetoe::characteristic_uuid< 0x8C8B4094, 0x0DE2, 0x499F, 0xA28A, 0x4EED5BC73CAB >,\n                bluetoe::bind_characteristic_value< std::uint8_t, &ape2 >\n            >,\n            bluetoe::characteristic<\n                bluetoe::characteristic_uuid< 0x8C8B4094, 0x0DE2, 0x499F, 0xA28A, 0x4EED5BC73CAC >,\n                bluetoe::bind_characteristic_value< std::uint8_t, &ape3 >\n            >\n        >,\n        bluetoe::no_gap_service_for_gatt_servers\n    > three_apes_service;\n\n    template < class ServerWithoutMTUSetting, std::size_t ResponseBufferSize = 23 >\n    struct request_with_reponse : bluetoe::extend_server< ServerWithoutMTUSetting, bluetoe::max_mtu_size< ResponseBufferSize > >\n    {\n        using server = bluetoe::extend_server< ServerWithoutMTUSetting, bluetoe::max_mtu_size< ResponseBufferSize > >;\n\n        enum {\n            fill_pattern = 0x55,\n            guard_size = 16\n        };\n\n        request_with_reponse()\n            : response( &guarded_buffer[ guard_size ] )\n            , response_size( ResponseBufferSize )\n            , connection()\n        {\n            connection.client_mtu( ResponseBufferSize );\n\n            notification = bluetoe::details::notification_data();\n            notification_type = bluetoe::details::notification_type::notification;\n\n            this->notification_callback( &l2cap_layer_notify_cb, this );\n        }\n\n        template < std::size_t PDU_Size >\n        void l2cap_input( const std::uint8_t(&input)[PDU_Size] )\n        {\n            response_size = ResponseBufferSize;\n            std::fill( std::begin( guarded_buffer ), std::end( guarded_buffer ), fill_pattern );\n            server::l2cap_input( input, PDU_Size, response, response_size, connection );\n            check_response();\n        }\n\n        template < class Connection >\n        void l2cap_input( const std::vector< std::uint8_t >& values, Connection& con = Connection() )\n        {\n            response_size = ResponseBufferSize;\n            std::fill( std::begin( guarded_buffer ), std::end( guarded_buffer ), fill_pattern );\n            server::l2cap_input( &values[ 0 ], values.size(), response, response_size, con );\n            check_response();\n        }\n\n        template < class Connection >\n        void l2cap_input( const std::initializer_list< std::uint8_t >& input, Connection& con )\n        {\n            const std::vector< std::uint8_t > values( input );\n            l2cap_input( values, con );\n        }\n\n        void l2cap_input( const std::initializer_list< std::uint8_t >& input )\n        {\n            l2cap_input( input, connection );\n        }\n\n        void expected_result( const std::initializer_list< std::uint8_t >& input )\n        {\n            const std::vector< std::uint8_t > values( input );\n            BOOST_REQUIRE_EQUAL_COLLECTIONS( values.begin(), values.end(), &response[ 0 ], &response[ response_size ] );\n        }\n\n        template < std::size_t PDU_Size >\n        bool check_error_response( const std::uint8_t(&input)[PDU_Size], std::uint8_t expected_request_opcode, std::uint16_t expected_attribute_handle, std::uint8_t expected_error_code )\n        {\n            return check_error_response_impl( &input[ 0 ], PDU_Size, expected_request_opcode, expected_attribute_handle, expected_error_code );\n        }\n\n        bool check_error_response( const std::initializer_list< std::uint8_t >& input, std::uint8_t expected_request_opcode, std::uint16_t expected_attribute_handle, std::uint8_t expected_error_code )\n        {\n            const std::vector< std::uint8_t > values( input );\n            return check_error_response_impl( &values[ 0 ], values.size(), expected_request_opcode, expected_attribute_handle, expected_error_code );\n        }\n\n        void dump()\n        {\n            hex_dump( std::cout, &response[ 0 ], &response[ response_size ] );\n        }\n\n        void dump_all()\n        {\n            hex_dump( std::cout, std::begin( guarded_buffer ), std::end( guarded_buffer ) );\n        }\n\n        template < class Iter, class Connection >\n        void expected_output( const bluetoe::details::notification_data& org_value, Iter begin, Iter end, Connection& con )\n        {\n            assert( org_value.valid() );\n\n            const std::vector< std::uint8_t > values( begin, end );\n            std::uint8_t buffer[ ResponseBufferSize ];\n            std::size_t  size = ResponseBufferSize;\n\n            this->l2cap_output( &buffer[ 0 ], size, con );\n\n            BOOST_REQUIRE_EQUAL_COLLECTIONS( values.begin(), values.end(), &buffer[ 0 ], &buffer[ size ] );\n        }\n\n        template < class Connection >\n        void expected_output( const bluetoe::details::notification_data& value, const std::initializer_list< std::uint8_t >& expected, Connection& con )\n        {\n            expected_output( value, expected.begin(), expected.end(), con );\n        }\n\n        void expected_output( const bluetoe::details::notification_data& value, const std::initializer_list< std::uint8_t >& expected )\n        {\n            expected_output( value, expected, connection );\n        }\n\n        template < class CharacteristicUUID >\n        void expected_output( const std::initializer_list< std::uint8_t >& expected )\n        {\n            expected_output( notification, expected );\n        }\n\n        template < class T, class Connection >\n        void expected_output( const T& value, const std::initializer_list< std::uint8_t >& expected, Connection& con )\n        {\n            expected_output( find_notification_data( &value ), expected, con );\n        }\n\n        template < class T >\n        void expected_output( const T& value, const std::initializer_list< std::uint8_t >& expected )\n        {\n            expected_output( find_notification_data( &value ), expected, connection );\n        }\n\n        const std::uint8_t* begin() const\n        {\n            return &guarded_buffer[ guard_size ];\n        }\n\n        std::uint8_t* begin()\n        {\n            return &guarded_buffer[ guard_size ];\n        }\n\n        const std::uint8_t* end() const\n        {\n            return &guarded_buffer[ ResponseBufferSize + guard_size ];\n        }\n\n        static_assert( ResponseBufferSize >= 23, \"min MTU size is 23, no point in using less\" );\n\n        using server::find_notification_data;\n        using connection_t = typename server::template channel_data_t< bluetoe::details::link_state >;\n\n        std::uint8_t                                guarded_buffer[ ResponseBufferSize + 2 * guard_size ];\n        std::uint8_t* const                         response;\n        std::size_t                                 response_size;\n        static constexpr std::size_t                mtu_size = ResponseBufferSize;\n        connection_t                                connection;\n\n        // TODO Should be removed and tests be based on the queue in connection\n        static bluetoe::details::notification_data  notification;\n        static bluetoe::details::notification_type  notification_type;\n\n    private:\n        void check_response() const\n        {\n            BOOST_REQUIRE_LE( response_size, ResponseBufferSize );\n            BOOST_CHECK( std::find_if( std::begin( guarded_buffer ), begin(),\n                []( std::uint8_t a ) -> bool { return a != fill_pattern; } ) == begin() );\n            BOOST_CHECK( std::find_if( end(), std::end( guarded_buffer ),\n                []( std::uint8_t a ) -> bool { return a != fill_pattern; } ) == std::end( guarded_buffer ) );\n        }\n\n        static bool l2cap_layer_notify_cb( const bluetoe::details::notification_data& item, void* that, typename bluetoe::details::notification_type type )\n        {\n            notification = item;\n            notification_type = type;\n\n            auto& connection = static_cast< request_with_reponse< ServerWithoutMTUSetting, ResponseBufferSize >* >( that )->connection;\n\n            switch ( type )\n            {\n                case bluetoe::details::notification_type::notification:\n                    return connection.queue_notification( item.client_characteristic_configuration_index() );\n                    break;\n                case bluetoe::details::notification_type::indication:\n                    return connection.queue_indication( item.client_characteristic_configuration_index() );\n                    break;\n                case bluetoe::details::notification_type::confirmation:\n                    connection.indication_confirmed();\n                    return true;\n                    break;\n            }\n\n            return true;\n        }\n\n        template < typename T >\n        std::string param_to_text( const T& param )\n        {\n            std::ostringstream out;\n            out << \"0x\" << std::hex << param;\n\n            return out.str();\n        }\n\n        std::string param_to_text( std::uint8_t c )\n        {\n            return param_to_text( static_cast< int >( c ) );\n        }\n\n        template < typename T, typename U >\n        std::string should_be_but( const char* text, const T& should, const U& but )\n        {\n            std::ostringstream out;\n            out << \"ATT: \\\"\" << text << \"\\\" should be \" << param_to_text( should ) << \" but is: \" <<  param_to_text( but );\n            return out.str();\n        }\n\n        bool check_error_response_impl( std::uint8_t const * input, std::size_t input_size, std::uint8_t expected_request_opcode, std::uint16_t expected_attribute_handle, std::uint8_t expected_error_code )\n        {\n            response_size = ResponseBufferSize;\n\n            server::l2cap_input( input, input_size, response, response_size, connection );\n\n            const std::uint8_t  opcode           = response[ 0 ];\n            const std::uint8_t  request_opcode   = response[ 1 ];\n            const std::uint16_t attribute_handle = response[ 2 ] + ( response[ 3 ] << 8 );\n            const std::uint8_t  error_code       = response[ 4 ];\n\n            BOOST_CHECK_MESSAGE( response_size == 5, should_be_but( \"PDU Size\", 5, response_size ) );\n            BOOST_CHECK_MESSAGE( opcode == 0x01, should_be_but( \"Attribute Opcode\", 0x01, opcode ) );\n            BOOST_CHECK_MESSAGE( request_opcode == expected_request_opcode, should_be_but( \"Request Opcode In Error\", expected_request_opcode, request_opcode ) );\n            BOOST_CHECK_MESSAGE( attribute_handle == expected_attribute_handle, should_be_but( \"Attribute Handle In Error\", expected_attribute_handle, attribute_handle ) );\n            BOOST_CHECK_MESSAGE( error_code == expected_error_code, should_be_but( \"Error Code\", expected_error_code, error_code ) );\n\n            return response_size == 5\n                && opcode == 0x01\n                && request_opcode == expected_request_opcode\n                && attribute_handle == expected_attribute_handle\n                && error_code == expected_error_code;\n        }\n    };\n\n    template < typename ServerWithoutMTUSetting, std::size_t ResponseBufferSize >\n    bluetoe::details::notification_data request_with_reponse< ServerWithoutMTUSetting, ResponseBufferSize >::notification;\n\n    template < typename ServerWithoutMTUSetting, std::size_t ResponseBufferSize >\n    bluetoe::details::notification_type request_with_reponse< ServerWithoutMTUSetting, ResponseBufferSize >::notification_type;\n\n    template < std::size_t ResponseBufferSize = 23 >\n    using small_temperature_service_with_response = request_with_reponse< small_temperature_service, ResponseBufferSize >;\n\n}\n\n#endif\n"
  },
  {
    "path": "tests/test_tools/test_services.hpp",
    "content": "#ifndef BLUETOE_TESTS_TEST_SERVICES_HPP\n#define BLUETOE_TESTS_TEST_SERVICES_HPP\n\n#include <bluetoe/service.hpp>\n#include <bluetoe/characteristic.hpp>\n\nnamespace test {\n    std::uint32_t global_temperature;\n\n    typedef bluetoe::service<\n        bluetoe::service_uuid< 0xF0426E52, 0x4450, 0x4F3B, 0xB058, 0x5BAB1191D92A >,\n        bluetoe::characteristic<\n            bluetoe::characteristic_uuid< 0x8C8B4094, 0x0DE2, 0x499F, 0xA28A, 0x4EED5BC73CAA >,\n            bluetoe::bind_characteristic_value< std::uint32_t, &global_temperature >\n        >\n    > global_temperature_service;\n\n    typedef bluetoe::service<\n        bluetoe::service_uuid< 0xF0426E52, 0x4450, 0x4F3B, 0xB058, 0x5BAB1191D92A >\n    > empty_service;\n\n    bool                characteristic_value_1 = 1;\n    const std::uint64_t characteristic_value_2 = 2;\n    const std::int16_t  characteristic_value_3 = 3;\n\n    typedef bluetoe::service<\n        bluetoe::service_uuid< 0x8C8B4094, 0x0DE2, 0x499F, 0xA28A, 0x4EED5BC73CA9 >,\n        bluetoe::characteristic<\n            bluetoe::characteristic_uuid< 0x8C8B4094, 0x0DE2, 0x499F, 0xA28A, 0x4EED5BC73CAA >,\n            bluetoe::bind_characteristic_value< decltype( characteristic_value_1 ), &characteristic_value_1 >,\n            bluetoe::no_read_access\n        >,\n        bluetoe::characteristic<\n            bluetoe::characteristic_uuid< 0x8C8B4094, 0x0DE2, 0x499F, 0xA28A, 0x4EED5BC73CAB >,\n            bluetoe::bind_characteristic_value< decltype( characteristic_value_2 ), &characteristic_value_2 >\n        >,\n        bluetoe::characteristic<\n            bluetoe::characteristic_uuid16< 0x0815 >,\n            bluetoe::bind_characteristic_value< decltype( characteristic_value_3 ), &characteristic_value_3 >\n        >\n    > service_with_3_characteristics;\n\n    std::uint32_t               csc_measurement = 0;\n    static const std::uint16_t  csc_feature     = 0;\n\n    typedef bluetoe::service<\n        bluetoe::service_uuid16< 0x1816 >,\n        bluetoe::characteristic<\n            bluetoe::characteristic_uuid16< 0x2A5B >,\n            bluetoe::bind_characteristic_value< decltype( csc_measurement ), &csc_measurement >\n        >,\n        bluetoe::characteristic<\n            bluetoe::characteristic_uuid16< 0x2A5C >,\n            bluetoe::bind_characteristic_value< decltype( csc_feature ), &csc_feature >\n        >\n    > cycling_speed_and_cadence_service;\n}\n\n#endif\n"
  },
  {
    "path": "tests/test_tools/test_uuid.cpp",
    "content": "#include \"test_uuid.hpp\"\n#include \"hexdump.hpp\"\n\n#include <cassert>\n\nnamespace test {\n\n    dynamic_uuid::dynamic_uuid()\n    {\n    }\n\n    dynamic_uuid::dynamic_uuid( const std::uint8_t* p, std::size_t s )\n        : uuid_( p, p + s )\n    {\n        assert( s == 2 || s == 16 );\n    }\n\n    bool dynamic_uuid::operator==( const dynamic_uuid& rhs ) const\n    {\n        return uuid_.size() == rhs.uuid_.size()\n            && std::equal( uuid_.begin(), uuid_.end(), rhs.uuid_.begin() );\n    }\n\n    void dynamic_uuid::print( std::ostream& o ) const\n    {\n        for ( auto c = uuid_.begin(); c != uuid_.end(); ++c )\n        {\n            print_hex( o, *c );\n\n            if ( c + 1 != uuid_.end() )\n                o << ':';\n        }\n    }\n\n    std::ostream& operator<<( std::ostream& out, const dynamic_uuid& uuid )\n    {\n        out << \"[\";\n        uuid.print( out );\n        out << \"]\";\n\n        return out;\n    }\n\n}\n"
  },
  {
    "path": "tests/test_tools/test_uuid.hpp",
    "content": "#ifndef BLUE_TESTS_TEST_UUID_HPP\n#define BLUE_TESTS_TEST_UUID_HPP\n\n#include <cstdint>\n#include <cstddef>\n#include <iosfwd>\n#include <vector>\n\nnamespace test {\n\n    class dynamic_uuid\n    {\n    public:\n        dynamic_uuid();\n\n        dynamic_uuid( const std::uint8_t*, std::size_t );\n\n        template < class UUID >\n        explicit dynamic_uuid( const UUID* )\n            : uuid_( std::begin( UUID::bytes ), std::end( UUID::bytes ) )\n        {\n        }\n\n        bool operator==( const dynamic_uuid& rhs ) const;\n        bool operator<( const dynamic_uuid& rhs ) const;\n        void print( std::ostream& ) const;\n\n    private:\n        std::vector< std::uint8_t > uuid_;\n    };\n\n    std::ostream& operator<<( std::ostream& out, const dynamic_uuid& );\n\n\n}\n\n#endif\n"
  },
  {
    "path": "tests/test_tools/uECC.c",
    "content": "/* Copyright 2014, Kenneth MacKay. Licensed under the BSD 2-clause license. */\n\n#include \"uECC.h\"\n\n#ifndef uECC_PLATFORM\n    #if __AVR__\n        #define uECC_PLATFORM uECC_avr\n    #elif defined(__thumb2__) || defined(_M_ARMT) /* I think MSVC only supports Thumb-2 targets */\n        #define uECC_PLATFORM uECC_arm_thumb2\n    #elif defined(__thumb__)\n        #define uECC_PLATFORM uECC_arm_thumb\n    #elif defined(__arm__) || defined(_M_ARM)\n        #define uECC_PLATFORM uECC_arm\n    #elif defined(__i386__) || defined(_M_IX86) || defined(_X86_) || defined(__I86__)\n        #define uECC_PLATFORM uECC_x86\n    #elif defined(__amd64__) || defined(_M_X64)\n        #define uECC_PLATFORM uECC_x86_64\n    #else\n        #define uECC_PLATFORM uECC_arch_other\n    #endif\n#endif\n\n#ifndef uECC_WORD_SIZE\n    #if uECC_PLATFORM == uECC_avr\n        #define uECC_WORD_SIZE 1\n    #elif (uECC_PLATFORM == uECC_x86_64)\n        #define uECC_WORD_SIZE 8\n    #else\n        #define uECC_WORD_SIZE 4\n    #endif\n#endif\n\n#if (uECC_CURVE == uECC_secp160r1 || uECC_CURVE == uECC_secp224r1) && (uECC_WORD_SIZE == 8)\n    #undef uECC_WORD_SIZE\n    #define uECC_WORD_SIZE 4\n    #if (uECC_PLATFORM == uECC_x86_64)\n        #undef uECC_PLATFORM\n        #define uECC_PLATFORM uECC_x86\n    #endif\n#endif\n\n#if (uECC_WORD_SIZE != 1) && (uECC_WORD_SIZE != 4) && (uECC_WORD_SIZE != 8)\n    #error \"Unsupported value for uECC_WORD_SIZE\"\n#endif\n\n#if (uECC_ASM && (uECC_PLATFORM == uECC_avr) && (uECC_WORD_SIZE != 1))\n    #pragma message (\"uECC_WORD_SIZE must be 1 when using AVR asm\")\n    #undef uECC_WORD_SIZE\n    #define uECC_WORD_SIZE 1\n#endif\n\n#if (uECC_ASM && \\\n     (uECC_PLATFORM == uECC_arm || uECC_PLATFORM == uECC_arm_thumb) && \\\n     (uECC_WORD_SIZE != 4))\n    #pragma message (\"uECC_WORD_SIZE must be 4 when using ARM asm\")\n    #undef uECC_WORD_SIZE\n    #define uECC_WORD_SIZE 4\n#endif\n\n#if __STDC_VERSION__ >= 199901L\n    #define RESTRICT restrict\n#else\n    #define RESTRICT\n#endif\n\n#if defined(__SIZEOF_INT128__) || ((__clang_major__ * 100 + __clang_minor__) >= 302)\n    #define SUPPORTS_INT128 1\n#else\n    #define SUPPORTS_INT128 0\n#endif\n\n#define MAX_TRIES 64\n\n#if (uECC_WORD_SIZE == 1)\n\ntypedef uint8_t uECC_word_t;\ntypedef uint16_t uECC_dword_t;\ntypedef uint8_t wordcount_t;\ntypedef int8_t swordcount_t;\ntypedef int16_t bitcount_t;\ntypedef int8_t cmpresult_t;\n\n#define HIGH_BIT_SET 0x80\n#define uECC_WORD_BITS 8\n#define uECC_WORD_BITS_SHIFT 3\n#define uECC_WORD_BITS_MASK 0x07\n\n#define uECC_WORDS_1 20\n#define uECC_WORDS_2 24\n#define uECC_WORDS_3 32\n#define uECC_WORDS_4 32\n#define uECC_WORDS_5 28\n\n#define uECC_N_WORDS_1 21\n#define uECC_N_WORDS_2 24\n#define uECC_N_WORDS_3 32\n#define uECC_N_WORDS_4 32\n#define uECC_N_WORDS_5 28\n\n#define Curve_P_1 {0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, \\\n                   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \\\n                   0xFF, 0xFF, 0xFF, 0xFF}\n#define Curve_P_2 {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \\\n                   0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \\\n                   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}\n#define Curve_P_3 {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \\\n                   0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, \\\n                   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \\\n                   0x01, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF}\n#define Curve_P_4 {0x2F, 0xFC, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, \\\n                   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \\\n                   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \\\n                   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}\n#define Curve_P_5 {0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \\\n                   0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, \\\n                   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \\\n                   0xFF, 0xFF, 0xFF, 0xFF}\n\n#define Curve_B_1 {0x45, 0xFA, 0x65, 0xC5, 0xAD, 0xD4, 0xD4, 0x81, \\\n                   0x9F, 0xF8, 0xAC, 0x65, 0x8B, 0x7A, 0xBD, 0x54, \\\n                   0xFC, 0xBE, 0x97, 0x1C}\n#define Curve_B_2 {0xB1, 0xB9, 0x46, 0xC1, 0xEC, 0xDE, 0xB8, 0xFE, \\\n                   0x49, 0x30, 0x24, 0x72, 0xAB, 0xE9, 0xA7, 0x0F, \\\n                   0xE7, 0x80, 0x9C, 0xE5, 0x19, 0x05, 0x21, 0x64}\n#define Curve_B_3 {0x4B, 0x60, 0xD2, 0x27, 0x3E, 0x3C, 0xCE, 0x3B, \\\n                   0xF6, 0xB0, 0x53, 0xCC, 0xB0, 0x06, 0x1D, 0x65, \\\n                   0xBC, 0x86, 0x98, 0x76, 0x55, 0xBD, 0xEB, 0xB3, \\\n                   0xE7, 0x93, 0x3A, 0xAA, 0xD8, 0x35, 0xC6, 0x5A}\n#define Curve_B_4 {0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \\\n                   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \\\n                   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \\\n                   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}\n#define Curve_B_5 {0xB4, 0xFF, 0x55, 0x23, 0x43, 0x39, 0x0B, 0x27, \\\n                   0xBA, 0xD8, 0xBF, 0xD7, 0xB7, 0xB0, 0x44, 0x50, \\\n                   0x56, 0x32, 0x41, 0xF5, 0xAB, 0xB3, 0x04, 0x0C, \\\n                   0x85, 0x0A, 0x05, 0xB4}\n\n#define Curve_G_1 { \\\n    {0x82, 0xFC, 0xCB, 0x13, 0xB9, 0x8B, 0xC3, 0x68, \\\n        0x89, 0x69, 0x64, 0x46, 0x28, 0x73, 0xF5, 0x8E, \\\n        0x68, 0xB5, 0x96, 0x4A}, \\\n    {0x32, 0xFB, 0xC5, 0x7A, 0x37, 0x51, 0x23, 0x04, \\\n        0x12, 0xC9, 0xDC, 0x59, 0x7D, 0x94, 0x68, 0x31, \\\n        0x55, 0x28, 0xA6, 0x23}}\n\n#define Curve_G_2 { \\\n    {0x12, 0x10, 0xFF, 0x82, 0xFD, 0x0A, 0xFF, 0xF4, \\\n        0x00, 0x88, 0xA1, 0x43, 0xEB, 0x20, 0xBF, 0x7C, \\\n        0xF6, 0x90, 0x30, 0xB0, 0x0E, 0xA8, 0x8D, 0x18}, \\\n    {0x11, 0x48, 0x79, 0x1E, 0xA1, 0x77, 0xF9, 0x73, \\\n        0xD5, 0xCD, 0x24, 0x6B, 0xED, 0x11, 0x10, 0x63, \\\n        0x78, 0xDA, 0xC8, 0xFF, 0x95, 0x2B, 0x19, 0x07}}\n\n#define Curve_G_3 { \\\n    {0x96, 0xC2, 0x98, 0xD8, 0x45, 0x39, 0xA1, 0xF4, \\\n        0xA0, 0x33, 0xEB, 0x2D, 0x81, 0x7D, 0x03, 0x77, \\\n        0xF2, 0x40, 0xA4, 0x63, 0xE5, 0xE6, 0xBC, 0xF8, \\\n        0x47, 0x42, 0x2C, 0xE1, 0xF2, 0xD1, 0x17, 0x6B}, \\\n    {0xF5, 0x51, 0xBF, 0x37, 0x68, 0x40, 0xB6, 0xCB, \\\n        0xCE, 0x5E, 0x31, 0x6B, 0x57, 0x33, 0xCE, 0x2B, \\\n        0x16, 0x9E, 0x0F, 0x7C, 0x4A, 0xEB, 0xE7, 0x8E, \\\n        0x9B, 0x7F, 0x1A, 0xFE, 0xE2, 0x42, 0xE3, 0x4F}}\n\n#define Curve_G_4 { \\\n    {0x98, 0x17, 0xF8, 0x16, 0x5B, 0x81, 0xF2, 0x59, \\\n        0xD9, 0x28, 0xCE, 0x2D, 0xDB, 0xFC, 0x9B, 0x02, \\\n        0x07, 0x0B, 0x87, 0xCE, 0x95, 0x62, 0xA0, 0x55, \\\n        0xAC, 0xBB, 0xDC, 0xF9, 0x7E, 0x66, 0xBE, 0x79}, \\\n    {0xB8, 0xD4, 0x10, 0xFB, 0x8F, 0xD0, 0x47, 0x9C, \\\n        0x19, 0x54, 0x85, 0xA6, 0x48, 0xB4, 0x17, 0xFD, \\\n        0xA8, 0x08, 0x11, 0x0E, 0xFC, 0xFB, 0xA4, 0x5D, \\\n        0x65, 0xC4, 0xA3, 0x26, 0x77, 0xDA, 0x3A, 0x48}}\n\n#define Curve_G_5 { \\\n    {0x21, 0x1D, 0x5C, 0x11, 0xD6, 0x80, 0x32, 0x34, \\\n        0x22, 0x11, 0xC2, 0x56, 0xD3, 0xC1, 0x03, 0x4A, \\\n        0xB9, 0x90, 0x13, 0x32, 0x7F, 0xBF, 0xB4, 0x6B, \\\n        0xBD, 0x0C, 0x0E, 0xB7}, \\\n    {0x34, 0x7E, 0x00, 0x85, 0x99, 0x81, 0xD5, 0x44, \\\n        0x64, 0x47, 0x07, 0x5A, 0xA0, 0x75, 0x43, 0xCD, \\\n        0xE6, 0xDF, 0x22, 0x4C, 0xFB, 0x23, 0xF7, 0xB5, \\\n        0x88, 0x63, 0x37, 0xBD}}\n\n#define Curve_N_1 {0x57, 0x22, 0x75, 0xCA, 0xD3, 0xAE, 0x27, 0xF9, \\\n                   0xC8, 0xF4, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, \\\n                   0x00, 0x00, 0x00, 0x00, 0x01}\n#define Curve_N_2 {0x31, 0x28, 0xD2, 0xB4, 0xB1, 0xC9, 0x6B, 0x14, \\\n                   0x36, 0xF8, 0xDE, 0x99, 0xFF, 0xFF, 0xFF, 0xFF, \\\n                   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}\n#define Curve_N_3 {0x51, 0x25, 0x63, 0xFC, 0xC2, 0xCA, 0xB9, 0xF3, \\\n                   0x84, 0x9E, 0x17, 0xA7, 0xAD, 0xFA, 0xE6, 0xBC, \\\n                   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \\\n                   0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF}\n#define Curve_N_4 {0x41, 0x41, 0x36, 0xD0, 0x8C, 0x5E, 0xD2, 0xBF, \\\n                   0x3B, 0xA0, 0x48, 0xAF, 0xE6, 0xDC, 0xAE, 0xBA, \\\n                   0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \\\n                   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}\n#define Curve_N_5 {0x3D, 0x2A, 0x5C, 0x5C, 0x45, 0x29, 0xDD, 0x13, \\\n                   0x3E, 0xF0, 0xB8, 0xE0, 0xA2, 0x16, 0xFF, 0xFF, \\\n                   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \\\n                   0xFF, 0xFF, 0xFF, 0xFF}\n\n#elif (uECC_WORD_SIZE == 4)\n\ntypedef uint32_t uECC_word_t;\ntypedef uint64_t uECC_dword_t;\ntypedef unsigned wordcount_t;\ntypedef int swordcount_t;\ntypedef int bitcount_t;\ntypedef int cmpresult_t;\n\n#define HIGH_BIT_SET 0x80000000\n#define uECC_WORD_BITS 32\n#define uECC_WORD_BITS_SHIFT 5\n#define uECC_WORD_BITS_MASK 0x01F\n\n#define uECC_WORDS_1 5\n#define uECC_WORDS_2 6\n#define uECC_WORDS_3 8\n#define uECC_WORDS_4 8\n#define uECC_WORDS_5 7\n\n#define uECC_N_WORDS_1 6\n#define uECC_N_WORDS_2 6\n#define uECC_N_WORDS_3 8\n#define uECC_N_WORDS_4 8\n#define uECC_N_WORDS_5 7\n\n#define Curve_P_1 {0x7FFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF}\n#define Curve_P_2 {0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF}\n#define Curve_P_3 {0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, \\\n                   0x00000000, 0x00000000, 0x00000001, 0xFFFFFFFF}\n#define Curve_P_4 {0xFFFFFC2F, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, \\\n                   0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF}\n#define Curve_P_5 {0x00000001, 0x00000000, 0x00000000, 0xFFFFFFFF, \\\n                   0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF}\n\n#define Curve_B_1 {0xC565FA45, 0x81D4D4AD, 0x65ACF89F, 0x54BD7A8B, 0x1C97BEFC}\n#define Curve_B_2 {0xC146B9B1, 0xFEB8DEEC, 0x72243049, 0x0FA7E9AB, 0xE59C80E7, 0x64210519}\n#define Curve_B_3 {0x27D2604B, 0x3BCE3C3E, 0xCC53B0F6, 0x651D06B0, \\\n                   0x769886BC, 0xB3EBBD55, 0xAA3A93E7, 0x5AC635D8}\n#define Curve_B_4 {0x00000007, 0x00000000, 0x00000000, 0x00000000, \\\n                   0x00000000, 0x00000000, 0x00000000, 0x00000000}\n#define Curve_B_5 {0x2355FFB4, 0x270B3943, 0xD7BFD8BA, 0x5044B0B7, \\\n                   0xF5413256, 0x0C04B3AB, 0xB4050A85}\n\n#define Curve_G_1 { \\\n    {0x13CBFC82, 0x68C38BB9, 0x46646989, 0x8EF57328, 0x4A96B568}, \\\n    {0x7AC5FB32, 0x04235137, 0x59DCC912, 0x3168947D, 0x23A62855}}\n\n#define Curve_G_2 { \\\n    {0x82FF1012, 0xF4FF0AFD, 0x43A18800, 0x7CBF20EB, 0xB03090F6, 0x188DA80E}, \\\n    {0x1E794811, 0x73F977A1, 0x6B24CDD5, 0x631011ED, 0xFFC8DA78, 0x07192B95}}\n\n#define Curve_G_3 { \\\n    {0xD898C296, 0xF4A13945, 0x2DEB33A0, 0x77037D81,  \\\n     0x63A440F2, 0xF8BCE6E5, 0xE12C4247, 0x6B17D1F2}, \\\n    {0x37BF51F5, 0xCBB64068, 0x6B315ECE, 0x2BCE3357,  \\\n     0x7C0F9E16, 0x8EE7EB4A, 0xFE1A7F9B, 0x4FE342E2}}\n\n#define Curve_G_4 { \\\n    {0x16F81798, 0x59F2815B, 0x2DCE28D9, 0x029BFCDB,  \\\n     0xCE870B07, 0x55A06295, 0xF9DCBBAC, 0x79BE667E}, \\\n    {0xFB10D4B8, 0x9C47D08F, 0xA6855419, 0xFD17B448,  \\\n     0x0E1108A8, 0x5DA4FBFC, 0x26A3C465, 0x483ADA77}}\n\n#define Curve_G_5 { \\\n    {0x115C1D21, 0x343280D6, 0x56C21122, 0x4A03C1D3, \\\n     0x321390B9, 0x6BB4BF7F, 0xB70E0CBD}, \\\n    {0x85007E34, 0x44D58199, 0x5A074764, 0xCD4375A0, \\\n     0x4C22DFE6, 0xB5F723FB, 0xBD376388}}\n\n#define Curve_N_1 {0xCA752257, 0xF927AED3, 0x0001F4C8, 0x00000000, 0x00000000, 0x00000001}\n#define Curve_N_2 {0xB4D22831, 0x146BC9B1, 0x99DEF836, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF}\n#define Curve_N_3 {0xFC632551, 0xF3B9CAC2, 0xA7179E84, 0xBCE6FAAD, \\\n                   0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF}\n#define Curve_N_4 {0xD0364141, 0xBFD25E8C, 0xAF48A03B, 0xBAAEDCE6, \\\n                   0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF}\n#define Curve_N_5 {0x5C5C2A3D, 0x13DD2945, 0xE0B8F03E, 0xFFFF16A2, \\\n                   0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF}\n\n#elif (uECC_WORD_SIZE == 8)\n\ntypedef uint64_t uECC_word_t;\n#if SUPPORTS_INT128\ntypedef unsigned __int128 uECC_dword_t;\n#endif\ntypedef unsigned wordcount_t;\ntypedef int swordcount_t;\ntypedef int bitcount_t;\ntypedef int cmpresult_t;\n\n#define HIGH_BIT_SET 0x8000000000000000ull\n#define uECC_WORD_BITS 64\n#define uECC_WORD_BITS_SHIFT 6\n#define uECC_WORD_BITS_MASK 0x03F\n\n#define uECC_WORDS_1 3\n#define uECC_WORDS_2 3\n#define uECC_WORDS_3 4\n#define uECC_WORDS_4 4\n#define uECC_WORDS_5 4\n\n#define uECC_N_WORDS_1 3\n#define uECC_N_WORDS_2 3\n#define uECC_N_WORDS_3 4\n#define uECC_N_WORDS_4 4\n#define uECC_N_WORDS_5 4\n\n#define Curve_P_1 {0xFFFFFFFF7FFFFFFFull, 0xFFFFFFFFFFFFFFFFull, 0x00000000FFFFFFFFull}\n#define Curve_P_2 {0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFEull, 0xFFFFFFFFFFFFFFFFull}\n#define Curve_P_3 {0xFFFFFFFFFFFFFFFFull, 0x00000000FFFFFFFFull, \\\n                   0x0000000000000000ull, 0xFFFFFFFF00000001ull}\n#define Curve_P_4 {0xFFFFFFFEFFFFFC2Full, 0xFFFFFFFFFFFFFFFFull, \\\n                   0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull}\n#define Curve_P_5 {0x0000000000000001ull, 0xFFFFFFFF00000000ull, \\\n                   0xFFFFFFFFFFFFFFFFull, 0x00000000FFFFFFFFull}\n\n#define Curve_B_1 {0x81D4D4ADC565FA45ull, 0x54BD7A8B65ACF89Full, 0x000000001C97BEFCull}\n#define Curve_B_2 {0xFEB8DEECC146B9B1ull, 0x0FA7E9AB72243049ull, 0x64210519E59C80E7ull}\n#define Curve_B_3 {0x3BCE3C3E27D2604Bull, 0x651D06B0CC53B0F6ull, \\\n                   0xB3EBBD55769886BCull, 0x5AC635D8AA3A93E7ull}\n#define Curve_B_4 {0x0000000000000007ull, 0x0000000000000000ull, \\\n                   0x0000000000000000ull, 0x0000000000000000ull}\n#define Curve_B_5 {0x270B39432355FFB4ull, 0x5044B0B7D7BFD8BAull, \\\n                   0x0C04B3ABF5413256ull, 0x00000000B4050A85ull}\n\n#define Curve_G_1 { \\\n    {0x68C38BB913CBFC82ull, 0x8EF5732846646989ull, 0x000000004A96B568ull}, \\\n    {0x042351377AC5FB32ull, 0x3168947D59DCC912ull, 0x0000000023A62855ull}}\n\n#define Curve_G_2 { \\\n    {0xF4FF0AFD82FF1012ull, 0x7CBF20EB43A18800ull, 0x188DA80EB03090F6ull}, \\\n    {0x73F977A11E794811ull, 0x631011ED6B24CDD5ull, 0x07192B95FFC8DA78ull}}\n\n#define Curve_G_3 { \\\n    {0xF4A13945D898C296ull, 0x77037D812DEB33A0ull, 0xF8BCE6E563A440F2ull, 0x6B17D1F2E12C4247ull}, \\\n    {0xCBB6406837BF51F5ull, 0x2BCE33576B315ECEull, 0x8EE7EB4A7C0F9E16ull, 0x4FE342E2FE1A7F9Bull}}\n\n#define Curve_G_4 { \\\n    {0x59F2815B16F81798ull, 0x029BFCDB2DCE28D9ull, 0x55A06295CE870B07ull, 0x79BE667EF9DCBBACull}, \\\n    {0x9C47D08FFB10D4B8ull, 0xFD17B448A6855419ull, 0x5DA4FBFC0E1108A8ull, 0x483ADA7726A3C465ull}}\n\n#define Curve_G_5 { \\\n    {0x343280D6115C1D21ull, 0x4A03C1D356C21122ull, 0x6BB4BF7F321390B9ull, 0x00000000B70E0CBDull}, \\\n    {0x44D5819985007E34ull, 0xCD4375A05A074764ull, 0xB5F723FB4C22DFE6ull, 0x00000000BD376388ull}}\n\n#define Curve_N_1 {0xF927AED3CA752257ull, 0x000000000001F4C8ull, 0x0000000100000000ull}\n#define Curve_N_2 {0x146BC9B1B4D22831ull, 0xFFFFFFFF99DEF836ull, 0xFFFFFFFFFFFFFFFFull}\n#define Curve_N_3 {0xF3B9CAC2FC632551ull, 0xBCE6FAADA7179E84ull, \\\n                   0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFF00000000ull}\n#define Curve_N_4 {0xBFD25E8CD0364141ull, 0xBAAEDCE6AF48A03Bull, \\\n                   0xFFFFFFFFFFFFFFFEull, 0xFFFFFFFFFFFFFFFFull}\n#define Curve_N_5 {0x13DD29455C5C2A3Dull, 0xFFFF16A2E0B8F03Eull, \\\n                   0xFFFFFFFFFFFFFFFFull, 0x00000000FFFFFFFFull}\n\n#endif /* (uECC_WORD_SIZE == 8) */\n\n#define uECC_WORDS uECC_CONCAT(uECC_WORDS_, uECC_CURVE)\n#define uECC_N_WORDS uECC_CONCAT(uECC_N_WORDS_, uECC_CURVE)\n\ntypedef struct EccPoint {\n    uECC_word_t x[uECC_WORDS];\n    uECC_word_t y[uECC_WORDS];\n} EccPoint;\n\nstatic const uECC_word_t curve_p[uECC_WORDS] = uECC_CONCAT(Curve_P_, uECC_CURVE);\nstatic const uECC_word_t curve_b[uECC_WORDS] = uECC_CONCAT(Curve_B_, uECC_CURVE);\nstatic const EccPoint curve_G = uECC_CONCAT(Curve_G_, uECC_CURVE);\nstatic const uECC_word_t curve_n[uECC_N_WORDS] = uECC_CONCAT(Curve_N_, uECC_CURVE);\n\nstatic void vli_clear(uECC_word_t *vli);\nstatic uECC_word_t vli_isZero(const uECC_word_t *vli);\nstatic uECC_word_t vli_testBit(const uECC_word_t *vli, bitcount_t bit);\nstatic bitcount_t vli_numBits(const uECC_word_t *vli, wordcount_t max_words);\nstatic void vli_set(uECC_word_t *dest, const uECC_word_t *src);\nstatic cmpresult_t vli_cmp(const uECC_word_t *left, const uECC_word_t *right);\nstatic cmpresult_t vli_equal(const uECC_word_t *left, const uECC_word_t *right);\nstatic void vli_rshift1(uECC_word_t *vli);\nstatic uECC_word_t vli_add(uECC_word_t *result,\n                           const uECC_word_t *left,\n                           const uECC_word_t *right);\nstatic uECC_word_t vli_sub(uECC_word_t *result,\n                           const uECC_word_t *left,\n                           const uECC_word_t *right);\nstatic void vli_mult(uECC_word_t *result, const uECC_word_t *left, const uECC_word_t *right);\nstatic void vli_modAdd(uECC_word_t *result,\n                       const uECC_word_t *left,\n                       const uECC_word_t *right,\n                       const uECC_word_t *mod);\nstatic void vli_modSub(uECC_word_t *result,\n                       const uECC_word_t *left,\n                       const uECC_word_t *right,\n                       const uECC_word_t *mod);\nstatic void vli_mmod_fast(uECC_word_t *RESTRICT result, uECC_word_t *RESTRICT product);\nstatic void vli_modMult_fast(uECC_word_t *result,\n                             const uECC_word_t *left,\n                             const uECC_word_t *right);\nstatic void vli_modInv(uECC_word_t *result, const uECC_word_t *input, const uECC_word_t *mod);\n#if uECC_SQUARE_FUNC\nstatic void vli_square(uECC_word_t *result, const uECC_word_t *left);\nstatic void vli_modSquare_fast(uECC_word_t *result, const uECC_word_t *left);\n#endif\n\n#if (defined(_WIN32) || defined(_WIN64))\n/* Windows */\n\n#define WIN32_LEAN_AND_MEAN\n#include <windows.h>\n#include <wincrypt.h>\n\nstatic int default_RNG(uint8_t *dest, unsigned size) {\n    HCRYPTPROV prov;\n    if (!CryptAcquireContext(&prov, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) {\n        return 0;\n    }\n\n    CryptGenRandom(prov, size, (BYTE *)dest);\n    CryptReleaseContext(prov, 0);\n    return 1;\n}\n\n#elif defined(unix) || defined(__linux__) || defined(__unix__) || defined(__unix) || \\\n    (defined(__APPLE__) && defined(__MACH__)) || defined(uECC_POSIX)\n\n/* Some POSIX-like system with /dev/urandom or /dev/random. */\n#include <sys/types.h>\n#include <fcntl.h>\n#include <unistd.h>\n\n#ifndef O_CLOEXEC\n    #define O_CLOEXEC 0\n#endif\n\nstatic int default_RNG(uint8_t *dest, unsigned size) {\n    int fd = open(\"/dev/urandom\", O_RDONLY | O_CLOEXEC);\n    if (fd == -1) {\n        fd = open(\"/dev/random\", O_RDONLY | O_CLOEXEC);\n        if (fd == -1) {\n            return 0;\n        }\n    }\n\n    char *ptr = (char *)dest;\n    size_t left = size;\n    while (left > 0) {\n        ssize_t bytes_read = read(fd, ptr, left);\n        if (bytes_read <= 0) { // read failed\n            close(fd);\n            return 0;\n        }\n        left -= bytes_read;\n        ptr += bytes_read;\n    }\n\n    close(fd);\n    return 1;\n}\n\n#else /* Some other platform */\n\nstatic int default_RNG(uint8_t *dest, unsigned size) {\n    return 0;\n}\n\n#endif\n\nstatic uECC_RNG_Function g_rng_function = &default_RNG;\n\nvoid uECC_set_rng(uECC_RNG_Function rng_function) {\n    g_rng_function = rng_function;\n}\n\n#ifdef __GNUC__ /* Only support GCC inline asm for now */\n    #if (uECC_ASM && (uECC_PLATFORM == uECC_avr))\n        #include \"asm_avr.inc\"\n    #endif\n\n    #if (uECC_ASM && (uECC_PLATFORM == uECC_arm || uECC_PLATFORM == uECC_arm_thumb || \\\n                      uECC_PLATFORM == uECC_arm_thumb2))\n        #include \"asm_arm.inc\"\n    #endif\n#endif\n\n#if !asm_clear\nstatic void vli_clear(uECC_word_t *vli) {\n    wordcount_t i;\n    for (i = 0; i < uECC_WORDS; ++i) {\n        vli[i] = 0;\n    }\n}\n#endif\n\n/* Returns 1 if vli == 0, 0 otherwise. */\n#if !asm_isZero\nstatic uECC_word_t vli_isZero(const uECC_word_t *vli) {\n    wordcount_t i;\n    for (i = 0; i < uECC_WORDS; ++i) {\n        if (vli[i]) {\n            return 0;\n        }\n    }\n    return 1;\n}\n#endif\n\n/* Returns nonzero if bit 'bit' of vli is set. */\n#if !asm_testBit\nstatic uECC_word_t vli_testBit(const uECC_word_t *vli, bitcount_t bit) {\n    return (vli[bit >> uECC_WORD_BITS_SHIFT] & ((uECC_word_t)1 << (bit & uECC_WORD_BITS_MASK)));\n}\n#endif\n\n/* Counts the number of words in vli. */\n#if !asm_numBits\nstatic wordcount_t vli_numDigits(const uECC_word_t *vli, wordcount_t max_words) {\n    swordcount_t i;\n    /* Search from the end until we find a non-zero digit.\n       We do it in reverse because we expect that most digits will be nonzero. */\n    for (i = max_words - 1; i >= 0 && vli[i] == 0; --i) {\n    }\n\n    return (i + 1);\n}\n\n/* Counts the number of bits required to represent vli. */\nstatic bitcount_t vli_numBits(const uECC_word_t *vli, wordcount_t max_words) {\n    uECC_word_t i;\n    uECC_word_t digit;\n\n    wordcount_t num_digits = vli_numDigits(vli, max_words);\n    if (num_digits == 0) {\n        return 0;\n    }\n\n    digit = vli[num_digits - 1];\n    for (i = 0; digit; ++i) {\n        digit >>= 1;\n    }\n\n    return (((bitcount_t)(num_digits - 1) << uECC_WORD_BITS_SHIFT) + i);\n}\n#endif /* !asm_numBits */\n\n/* Sets dest = src. */\n#if !asm_set\nstatic void vli_set(uECC_word_t *dest, const uECC_word_t *src) {\n    wordcount_t i;\n    for (i = 0; i < uECC_WORDS; ++i) {\n        dest[i] = src[i];\n    }\n}\n#endif\n\n/* Returns sign of left - right. */\n#if !asm_cmp\nstatic cmpresult_t vli_cmp(const uECC_word_t *left, const uECC_word_t *right) {\n    swordcount_t i;\n    for (i = uECC_WORDS - 1; i >= 0; --i) {\n        if (left[i] > right[i]) {\n            return 1;\n        } else if (left[i] < right[i]) {\n            return -1;\n        }\n    }\n    return 0;\n}\n#endif\n\nstatic cmpresult_t vli_equal(const uECC_word_t *left, const uECC_word_t *right) {\n    uECC_word_t result = 0;\n    swordcount_t i;\n    for (i = uECC_WORDS - 1; i >= 0; --i) {\n        result |= (left[i] ^ right[i]);\n    }\n    return (result == 0);\n}\n\n/* Computes vli = vli >> 1. */\n#if !asm_rshift1\nstatic void vli_rshift1(uECC_word_t *vli) {\n    uECC_word_t *end = vli;\n    uECC_word_t carry = 0;\n\n    vli += uECC_WORDS;\n    while (vli-- > end) {\n        uECC_word_t temp = *vli;\n        *vli = (temp >> 1) | carry;\n        carry = temp << (uECC_WORD_BITS - 1);\n    }\n}\n#endif\n\n/* Computes result = left + right, returning carry. Can modify in place. */\n#if !asm_add\nstatic uECC_word_t vli_add(uECC_word_t *result, const uECC_word_t *left, const uECC_word_t *right) {\n    uECC_word_t carry = 0;\n    wordcount_t i;\n    for (i = 0; i < uECC_WORDS; ++i) {\n        uECC_word_t sum = left[i] + right[i] + carry;\n        if (sum != left[i]) {\n            carry = (sum < left[i]);\n        }\n        result[i] = sum;\n    }\n    return carry;\n}\n#endif\n\n/* Computes result = left - right, returning borrow. Can modify in place. */\n#if !asm_sub\nstatic uECC_word_t vli_sub(uECC_word_t *result, const uECC_word_t *left, const uECC_word_t *right) {\n    uECC_word_t borrow = 0;\n    wordcount_t i;\n    for (i = 0; i < uECC_WORDS; ++i) {\n        uECC_word_t diff = left[i] - right[i] - borrow;\n        if (diff != left[i]) {\n            borrow = (diff > left[i]);\n        }\n        result[i] = diff;\n    }\n    return borrow;\n}\n#endif\n\n#if (!asm_mult || (uECC_SQUARE_FUNC && !asm_square) || uECC_CURVE == uECC_secp256k1)\nstatic void muladd(uECC_word_t a,\n                   uECC_word_t b,\n                   uECC_word_t *r0,\n                   uECC_word_t *r1,\n                   uECC_word_t *r2) {\n#if uECC_WORD_SIZE == 8 && !SUPPORTS_INT128\n    uint64_t a0 = a & 0xffffffffull;\n    uint64_t a1 = a >> 32;\n    uint64_t b0 = b & 0xffffffffull;\n    uint64_t b1 = b >> 32;\n\n    uint64_t i0 = a0 * b0;\n    uint64_t i1 = a0 * b1;\n    uint64_t i2 = a1 * b0;\n    uint64_t i3 = a1 * b1;\n\n    uint64_t p0, p1;\n\n    i2 += (i0 >> 32);\n    i2 += i1;\n    if (i2 < i1) { // overflow\n        i3 += 0x100000000ull;\n    }\n\n    p0 = (i0 & 0xffffffffull) | (i2 << 32);\n    p1 = i3 + (i2 >> 32);\n\n    *r0 += p0;\n    *r1 += (p1 + (*r0 < p0));\n    *r2 += ((*r1 < p1) || (*r1 == p1 && *r0 < p0));\n#else\n    uECC_dword_t p = (uECC_dword_t)a * b;\n    uECC_dword_t r01 = ((uECC_dword_t)(*r1) << uECC_WORD_BITS) | *r0;\n    r01 += p;\n    *r2 += (r01 < p);\n    *r1 = r01 >> uECC_WORD_BITS;\n    *r0 = (uECC_word_t)r01;\n#endif\n}\n#define muladd_exists 1\n#endif\n\n#if !asm_mult\nstatic void vli_mult(uECC_word_t *result, const uECC_word_t *left, const uECC_word_t *right) {\n    uECC_word_t r0 = 0;\n    uECC_word_t r1 = 0;\n    uECC_word_t r2 = 0;\n    wordcount_t i, k;\n\n    /* Compute each digit of result in sequence, maintaining the carries. */\n    for (k = 0; k < uECC_WORDS; ++k) {\n        for (i = 0; i <= k; ++i) {\n            muladd(left[i], right[k - i], &r0, &r1, &r2);\n        }\n        result[k] = r0;\n        r0 = r1;\n        r1 = r2;\n        r2 = 0;\n    }\n    for (k = uECC_WORDS; k < uECC_WORDS * 2 - 1; ++k) {\n        for (i = (k + 1) - uECC_WORDS; i < uECC_WORDS; ++i) {\n            muladd(left[i], right[k - i], &r0, &r1, &r2);\n        }\n        result[k] = r0;\n        r0 = r1;\n        r1 = r2;\n        r2 = 0;\n    }\n    result[uECC_WORDS * 2 - 1] = r0;\n}\n#endif\n\n#if uECC_SQUARE_FUNC\n\n#if !asm_square\nstatic void mul2add(uECC_word_t a,\n                    uECC_word_t b,\n                    uECC_word_t *r0,\n                    uECC_word_t *r1,\n                    uECC_word_t *r2) {\n#if uECC_WORD_SIZE == 8 && !SUPPORTS_INT128\n    uint64_t a0 = a & 0xffffffffull;\n    uint64_t a1 = a >> 32;\n    uint64_t b0 = b & 0xffffffffull;\n    uint64_t b1 = b >> 32;\n\n    uint64_t i0 = a0 * b0;\n    uint64_t i1 = a0 * b1;\n    uint64_t i2 = a1 * b0;\n    uint64_t i3 = a1 * b1;\n\n    uint64_t p0, p1;\n\n    i2 += (i0 >> 32);\n    i2 += i1;\n    if (i2 < i1)\n    { // overflow\n        i3 += 0x100000000ull;\n    }\n\n    p0 = (i0 & 0xffffffffull) | (i2 << 32);\n    p1 = i3 + (i2 >> 32);\n\n    *r2 += (p1 >> 63);\n    p1 = (p1 << 1) | (p0 >> 63);\n    p0 <<= 1;\n\n    *r0 += p0;\n    *r1 += (p1 + (*r0 < p0));\n    *r2 += ((*r1 < p1) || (*r1 == p1 && *r0 < p0));\n#else\n    uECC_dword_t p = (uECC_dword_t)a * b;\n    uECC_dword_t r01 = ((uECC_dword_t)(*r1) << uECC_WORD_BITS) | *r0;\n    *r2 += (p >> (uECC_WORD_BITS * 2 - 1));\n    p *= 2;\n    r01 += p;\n    *r2 += (r01 < p);\n    *r1 = r01 >> uECC_WORD_BITS;\n    *r0 = (uECC_word_t)r01;\n#endif\n}\n\nstatic void vli_square(uECC_word_t *result, const uECC_word_t *left) {\n    uECC_word_t r0 = 0;\n    uECC_word_t r1 = 0;\n    uECC_word_t r2 = 0;\n\n    wordcount_t i, k;\n\n    for (k = 0; k < uECC_WORDS * 2 - 1; ++k) {\n        uECC_word_t min = (k < uECC_WORDS ? 0 : (k + 1) - uECC_WORDS);\n        for (i = min; i <= k && i <= k - i; ++i) {\n            if (i < k-i) {\n                mul2add(left[i], left[k - i], &r0, &r1, &r2);\n            } else {\n                muladd(left[i], left[k - i], &r0, &r1, &r2);\n            }\n        }\n        result[k] = r0;\n        r0 = r1;\n        r1 = r2;\n        r2 = 0;\n    }\n\n    result[uECC_WORDS * 2 - 1] = r0;\n}\n#endif\n\n#else /* uECC_SQUARE_FUNC */\n\n#define vli_square(result, left, size) vli_mult((result), (left), (left), (size))\n\n#endif /* uECC_SQUARE_FUNC */\n\n\n/* Computes result = (left + right) % mod.\n   Assumes that left < mod and right < mod, and that result does not overlap mod. */\n#if !asm_modAdd\nstatic void vli_modAdd(uECC_word_t *result,\n                       const uECC_word_t *left,\n                       const uECC_word_t *right,\n                       const uECC_word_t *mod) {\n    uECC_word_t carry = vli_add(result, left, right);\n    if (carry || vli_cmp(result, mod) >= 0) {\n        /* result > mod (result = mod + remainder), so subtract mod to get remainder. */\n        vli_sub(result, result, mod);\n    }\n}\n#endif\n\n/* Computes result = (left - right) % mod.\n   Assumes that left < mod and right < mod, and that result does not overlap mod. */\n#if !asm_modSub\nstatic void vli_modSub(uECC_word_t *result,\n                       const uECC_word_t *left,\n                       const uECC_word_t *right,\n                       const uECC_word_t *mod) {\n    uECC_word_t l_borrow = vli_sub(result, left, right);\n    if (l_borrow) {\n        /* In this case, result == -diff == (max int) - diff. Since -x % d == d - x,\n           we can get the correct result from result + mod (with overflow). */\n        vli_add(result, result, mod);\n    }\n}\n#endif\n\n#if !asm_modSub_fast\n    #define vli_modSub_fast(result, left, right) vli_modSub((result), (left), (right), curve_p)\n#endif\n\n#if !asm_mmod_fast\n\n#if (uECC_CURVE == uECC_secp160r1 || uECC_CURVE == uECC_secp256k1)\n/* omega_mult() is defined farther below for the different curves / word sizes */\nstatic void omega_mult(uECC_word_t * RESTRICT result, const uECC_word_t * RESTRICT right);\n\n/* Computes result = product % curve_p\n    see http://www.isys.uni-klu.ac.at/PDF/2001-0126-MT.pdf page 354\n\n    Note that this only works if log2(omega) < log2(p) / 2 */\nstatic void vli_mmod_fast(uECC_word_t *RESTRICT result, uECC_word_t *RESTRICT product) {\n    uECC_word_t tmp[2 * uECC_WORDS];\n    uECC_word_t carry;\n\n    vli_clear(tmp);\n    vli_clear(tmp + uECC_WORDS);\n\n    omega_mult(tmp, product + uECC_WORDS); /* (Rq, q) = q * c */\n\n    carry = vli_add(result, product, tmp); /* (C, r) = r + q       */\n    vli_clear(product);\n    omega_mult(product, tmp + uECC_WORDS); /* Rq*c */\n    carry += vli_add(result, result, product); /* (C1, r) = r + Rq*c */\n\n    while (carry > 0) {\n        --carry;\n        vli_sub(result, result, curve_p);\n    }\n    if (vli_cmp(result, curve_p) > 0) {\n        vli_sub(result, result, curve_p);\n    }\n}\n\n#endif\n\n#if uECC_CURVE == uECC_secp160r1\n\n#if uECC_WORD_SIZE == 1\nstatic void omega_mult(uint8_t * RESTRICT result, const uint8_t * RESTRICT right) {\n    uint8_t carry;\n    uint8_t i;\n\n    /* Multiply by (2^31 + 1). */\n    vli_set(result + 4, right); /* 2^32 */\n    vli_rshift1(result + 4); /* 2^31 */\n    result[3] = right[0] << 7; /* get last bit from shift */\n\n    carry = vli_add(result, result, right); /* 2^31 + 1 */\n    for (i = uECC_WORDS; carry; ++i) {\n        uint16_t sum = (uint16_t)result[i] + carry;\n        result[i] = (uint8_t)sum;\n        carry = sum >> 8;\n    }\n}\n#elif uECC_WORD_SIZE == 4\nstatic void omega_mult(uint32_t * RESTRICT result, const uint32_t * RESTRICT right) {\n    uint32_t carry;\n    unsigned i;\n\n    /* Multiply by (2^31 + 1). */\n    vli_set(result + 1, right); /* 2^32 */\n    vli_rshift1(result + 1); /* 2^31 */\n    result[0] = right[0] << 31; /* get last bit from shift */\n\n    carry = vli_add(result, result, right); /* 2^31 + 1 */\n    for (i = uECC_WORDS; carry; ++i) {\n        uint64_t sum = (uint64_t)result[i] + carry;\n        result[i] = (uint32_t)sum;\n        carry = sum >> 32;\n    }\n}\n#endif /* uECC_WORD_SIZE */\n\n#elif uECC_CURVE == uECC_secp192r1\n\n/* Computes result = product % curve_p.\n   See algorithm 5 and 6 from http://www.isys.uni-klu.ac.at/PDF/2001-0126-MT.pdf */\n#if uECC_WORD_SIZE == 1\nstatic void vli_mmod_fast(uint8_t *RESTRICT result, uint8_t *RESTRICT product) {\n    uint8_t tmp[uECC_WORDS];\n    uint8_t carry;\n\n    vli_set(result, product);\n\n    vli_set(tmp, &product[24]);\n    carry = vli_add(result, result, tmp);\n\n    tmp[0] = tmp[1] = tmp[2] = tmp[3] = tmp[4] = tmp[5] = tmp[6] = tmp[7] = 0;\n    tmp[8] = product[24]; tmp[9] = product[25]; tmp[10] = product[26]; tmp[11] = product[27];\n    tmp[12] = product[28]; tmp[13] = product[29]; tmp[14] = product[30]; tmp[15] = product[31];\n    tmp[16] = product[32]; tmp[17] = product[33]; tmp[18] = product[34]; tmp[19] = product[35];\n    tmp[20] = product[36]; tmp[21] = product[37]; tmp[22] = product[38]; tmp[23] = product[39];\n    carry += vli_add(result, result, tmp);\n\n    tmp[0] = tmp[8] = product[40];\n    tmp[1] = tmp[9] = product[41];\n    tmp[2] = tmp[10] = product[42];\n    tmp[3] = tmp[11] = product[43];\n    tmp[4] = tmp[12] = product[44];\n    tmp[5] = tmp[13] = product[45];\n    tmp[6] = tmp[14] = product[46];\n    tmp[7] = tmp[15] = product[47];\n    tmp[16] = tmp[17] = tmp[18] = tmp[19] = tmp[20] = tmp[21] = tmp[22] = tmp[23] = 0;\n    carry += vli_add(result, result, tmp);\n\n    while (carry || vli_cmp(curve_p, result) != 1) {\n        carry -= vli_sub(result, result, curve_p);\n    }\n}\n#elif uECC_WORD_SIZE == 4\nstatic void vli_mmod_fast(uint32_t *RESTRICT result, uint32_t *RESTRICT product) {\n    uint32_t tmp[uECC_WORDS];\n    int carry;\n\n    vli_set(result, product);\n\n    vli_set(tmp, &product[6]);\n    carry = vli_add(result, result, tmp);\n\n    tmp[0] = tmp[1] = 0;\n    tmp[2] = product[6];\n    tmp[3] = product[7];\n    tmp[4] = product[8];\n    tmp[5] = product[9];\n    carry += vli_add(result, result, tmp);\n\n    tmp[0] = tmp[2] = product[10];\n    tmp[1] = tmp[3] = product[11];\n    tmp[4] = tmp[5] = 0;\n    carry += vli_add(result, result, tmp);\n\n    while (carry || vli_cmp(curve_p, result) != 1) {\n        carry -= vli_sub(result, result, curve_p);\n    }\n}\n#else\nstatic void vli_mmod_fast(uint64_t *RESTRICT result, uint64_t *RESTRICT product) {\n    uint64_t tmp[uECC_WORDS];\n    int carry;\n\n    vli_set(result, product);\n\n    vli_set(tmp, &product[3]);\n    carry = vli_add(result, result, tmp);\n\n    tmp[0] = 0;\n    tmp[1] = product[3];\n    tmp[2] = product[4];\n    carry += vli_add(result, result, tmp);\n\n    tmp[0] = tmp[1] = product[5];\n    tmp[2] = 0;\n    carry += vli_add(result, result, tmp);\n\n    while (carry || vli_cmp(curve_p, result) != 1) {\n        carry -= vli_sub(result, result, curve_p);\n    }\n}\n#endif /* uECC_WORD_SIZE */\n\n#elif uECC_CURVE == uECC_secp256r1\n\n/* Computes result = product % curve_p\n   from http://www.nsa.gov/ia/_files/nist-routines.pdf */\n#if uECC_WORD_SIZE == 1\nstatic void vli_mmod_fast(uint8_t *RESTRICT result, uint8_t *RESTRICT product) {\n    uint8_t tmp[uECC_BYTES];\n    int8_t carry;\n\n    /* t */\n    vli_set(result, product);\n\n    /* s1 */\n    tmp[0] = tmp[1] = tmp[2] = tmp[3] = 0;\n    tmp[4] = tmp[5] = tmp[6] = tmp[7] = 0;\n    tmp[8] = tmp[9] = tmp[10] = tmp[11] = 0;\n    tmp[12] = product[44]; tmp[13] = product[45]; tmp[14] = product[46]; tmp[15] = product[47];\n    tmp[16] = product[48]; tmp[17] = product[49]; tmp[18] = product[50]; tmp[19] = product[51];\n    tmp[20] = product[52]; tmp[21] = product[53]; tmp[22] = product[54]; tmp[23] = product[55];\n    tmp[24] = product[56]; tmp[25] = product[57]; tmp[26] = product[58]; tmp[27] = product[59];\n    tmp[28] = product[60]; tmp[29] = product[61]; tmp[30] = product[62]; tmp[31] = product[63];\n    carry = vli_add(tmp, tmp, tmp);\n    carry += vli_add(result, result, tmp);\n\n    /* s2 */\n    tmp[12] = product[48]; tmp[13] = product[49]; tmp[14] = product[50]; tmp[15] = product[51];\n    tmp[16] = product[52]; tmp[17] = product[53]; tmp[18] = product[54]; tmp[19] = product[55];\n    tmp[20] = product[56]; tmp[21] = product[57]; tmp[22] = product[58]; tmp[23] = product[59];\n    tmp[24] = product[60]; tmp[25] = product[61]; tmp[26] = product[62]; tmp[27] = product[63];\n    tmp[28] = tmp[29] = tmp[30] = tmp[31] = 0;\n    carry += vli_add(tmp, tmp, tmp);\n    carry += vli_add(result, result, tmp);\n\n    /* s3 */\n    tmp[0] = product[32]; tmp[1] = product[33]; tmp[2] = product[34]; tmp[3] = product[35];\n    tmp[4] = product[36]; tmp[5] = product[37]; tmp[6] = product[38]; tmp[7] = product[39];\n    tmp[8] = product[40]; tmp[9] = product[41]; tmp[10] = product[42]; tmp[11] = product[43];\n    tmp[12] = tmp[13] = tmp[14] = tmp[15] = 0;\n    tmp[16] = tmp[17] = tmp[18] = tmp[19] = 0;\n    tmp[20] = tmp[21] = tmp[22] = tmp[23] = 0;\n    tmp[24] = product[56]; tmp[25] = product[57]; tmp[26] = product[58]; tmp[27] = product[59];\n    tmp[28] = product[60]; tmp[29] = product[61]; tmp[30] = product[62]; tmp[31] = product[63];\n    carry += vli_add(result, result, tmp);\n\n    /* s4 */\n    tmp[0] = product[36]; tmp[1] = product[37]; tmp[2] = product[38]; tmp[3] = product[39];\n    tmp[4] = product[40]; tmp[5] = product[41]; tmp[6] = product[42]; tmp[7] = product[43];\n    tmp[8] = product[44]; tmp[9] = product[45]; tmp[10] = product[46]; tmp[11] = product[47];\n    tmp[12] = product[52]; tmp[13] = product[53]; tmp[14] = product[54]; tmp[15] = product[55];\n    tmp[16] = product[56]; tmp[17] = product[57]; tmp[18] = product[58]; tmp[19] = product[59];\n    tmp[20] = product[60]; tmp[21] = product[61]; tmp[22] = product[62]; tmp[23] = product[63];\n    tmp[24] = product[52]; tmp[25] = product[53]; tmp[26] = product[54]; tmp[27] = product[55];\n    tmp[28] = product[32]; tmp[29] = product[33]; tmp[30] = product[34]; tmp[31] = product[35];\n    carry += vli_add(result, result, tmp);\n\n    /* d1 */\n    tmp[0] = product[44]; tmp[1] = product[45]; tmp[2] = product[46]; tmp[3] = product[47];\n    tmp[4] = product[48]; tmp[5] = product[49]; tmp[6] = product[50]; tmp[7] = product[51];\n    tmp[8] = product[52]; tmp[9] = product[53]; tmp[10] = product[54]; tmp[11] = product[55];\n    tmp[12] = tmp[13] = tmp[14] = tmp[15] = 0;\n    tmp[16] = tmp[17] = tmp[18] = tmp[19] = 0;\n    tmp[20] = tmp[21] = tmp[22] = tmp[23] = 0;\n    tmp[24] = product[32]; tmp[25] = product[33]; tmp[26] = product[34]; tmp[27] = product[35];\n    tmp[28] = product[40]; tmp[29] = product[41]; tmp[30] = product[42]; tmp[31] = product[43];\n    carry -= vli_sub(result, result, tmp);\n\n    /* d2 */\n    tmp[0] = product[48]; tmp[1] = product[49]; tmp[2] = product[50]; tmp[3] = product[51];\n    tmp[4] = product[52]; tmp[5] = product[53]; tmp[6] = product[54]; tmp[7] = product[55];\n    tmp[8] = product[56]; tmp[9] = product[57]; tmp[10] = product[58]; tmp[11] = product[59];\n    tmp[12] = product[60]; tmp[13] = product[61]; tmp[14] = product[62]; tmp[15] = product[63];\n    tmp[16] = tmp[17] = tmp[18] = tmp[19] = 0;\n    tmp[20] = tmp[21] = tmp[22] = tmp[23] = 0;\n    tmp[24] = product[36]; tmp[25] = product[37]; tmp[26] = product[38]; tmp[27] = product[39];\n    tmp[28] = product[44]; tmp[29] = product[45]; tmp[30] = product[46]; tmp[31] = product[47];\n    carry -= vli_sub(result, result, tmp);\n\n    /* d3 */\n    tmp[0] = product[52]; tmp[1] = product[53]; tmp[2] = product[54]; tmp[3] = product[55];\n    tmp[4] = product[56]; tmp[5] = product[57]; tmp[6] = product[58]; tmp[7] = product[59];\n    tmp[8] = product[60]; tmp[9] = product[61]; tmp[10] = product[62]; tmp[11] = product[63];\n    tmp[12] = product[32]; tmp[13] = product[33]; tmp[14] = product[34]; tmp[15] = product[35];\n    tmp[16] = product[36]; tmp[17] = product[37]; tmp[18] = product[38]; tmp[19] = product[39];\n    tmp[20] = product[40]; tmp[21] = product[41]; tmp[22] = product[42]; tmp[23] = product[43];\n    tmp[24] = tmp[25] = tmp[26] = tmp[27] = 0;\n    tmp[28] = product[48]; tmp[29] = product[49]; tmp[30] = product[50]; tmp[31] = product[51];\n    carry -= vli_sub(result, result, tmp);\n\n    /* d4 */\n    tmp[0] = product[56]; tmp[1] = product[57]; tmp[2] = product[58]; tmp[3] = product[59];\n    tmp[4] = product[60]; tmp[5] = product[61]; tmp[6] = product[62]; tmp[7] = product[63];\n    tmp[8] = tmp[9] = tmp[10] = tmp[11] = 0;\n    tmp[12] = product[36]; tmp[13] = product[37]; tmp[14] = product[38]; tmp[15] = product[39];\n    tmp[16] = product[40]; tmp[17] = product[41]; tmp[18] = product[42]; tmp[19] = product[43];\n    tmp[20] = product[44]; tmp[21] = product[45]; tmp[22] = product[46]; tmp[23] = product[47];\n    tmp[24] = tmp[25] = tmp[26] = tmp[27] = 0;\n    tmp[28] = product[52]; tmp[29] = product[53]; tmp[30] = product[54]; tmp[31] = product[55];\n    carry -= vli_sub(result, result, tmp);\n\n    if (carry < 0) {\n        do {\n            carry += vli_add(result, result, curve_p);\n        } while (carry < 0);\n    } else {\n        while (carry || vli_cmp(curve_p, result) != 1) {\n            carry -= vli_sub(result, result, curve_p);\n        }\n    }\n}\n#elif uECC_WORD_SIZE == 4\nstatic void vli_mmod_fast(uint32_t *RESTRICT result, uint32_t *RESTRICT product) {\n    uint32_t tmp[uECC_WORDS];\n    int carry;\n\n    /* t */\n    vli_set(result, product);\n\n    /* s1 */\n    tmp[0] = tmp[1] = tmp[2] = 0;\n    tmp[3] = product[11];\n    tmp[4] = product[12];\n    tmp[5] = product[13];\n    tmp[6] = product[14];\n    tmp[7] = product[15];\n    carry = vli_add(tmp, tmp, tmp);\n    carry += vli_add(result, result, tmp);\n\n    /* s2 */\n    tmp[3] = product[12];\n    tmp[4] = product[13];\n    tmp[5] = product[14];\n    tmp[6] = product[15];\n    tmp[7] = 0;\n    carry += vli_add(tmp, tmp, tmp);\n    carry += vli_add(result, result, tmp);\n\n    /* s3 */\n    tmp[0] = product[8];\n    tmp[1] = product[9];\n    tmp[2] = product[10];\n    tmp[3] = tmp[4] = tmp[5] = 0;\n    tmp[6] = product[14];\n    tmp[7] = product[15];\n    carry += vli_add(result, result, tmp);\n\n    /* s4 */\n    tmp[0] = product[9];\n    tmp[1] = product[10];\n    tmp[2] = product[11];\n    tmp[3] = product[13];\n    tmp[4] = product[14];\n    tmp[5] = product[15];\n    tmp[6] = product[13];\n    tmp[7] = product[8];\n    carry += vli_add(result, result, tmp);\n\n    /* d1 */\n    tmp[0] = product[11];\n    tmp[1] = product[12];\n    tmp[2] = product[13];\n    tmp[3] = tmp[4] = tmp[5] = 0;\n    tmp[6] = product[8];\n    tmp[7] = product[10];\n    carry -= vli_sub(result, result, tmp);\n\n    /* d2 */\n    tmp[0] = product[12];\n    tmp[1] = product[13];\n    tmp[2] = product[14];\n    tmp[3] = product[15];\n    tmp[4] = tmp[5] = 0;\n    tmp[6] = product[9];\n    tmp[7] = product[11];\n    carry -= vli_sub(result, result, tmp);\n\n    /* d3 */\n    tmp[0] = product[13];\n    tmp[1] = product[14];\n    tmp[2] = product[15];\n    tmp[3] = product[8];\n    tmp[4] = product[9];\n    tmp[5] = product[10];\n    tmp[6] = 0;\n    tmp[7] = product[12];\n    carry -= vli_sub(result, result, tmp);\n\n    /* d4 */\n    tmp[0] = product[14];\n    tmp[1] = product[15];\n    tmp[2] = 0;\n    tmp[3] = product[9];\n    tmp[4] = product[10];\n    tmp[5] = product[11];\n    tmp[6] = 0;\n    tmp[7] = product[13];\n    carry -= vli_sub(result, result, tmp);\n\n    if (carry < 0) {\n        do {\n            carry += vli_add(result, result, curve_p);\n        } while (carry < 0);\n    } else {\n        while (carry || vli_cmp(curve_p, result) != 1) {\n            carry -= vli_sub(result, result, curve_p);\n        }\n    }\n}\n#else\nstatic void vli_mmod_fast(uint64_t *RESTRICT result, uint64_t *RESTRICT product) {\n    uint64_t tmp[uECC_WORDS];\n    int carry;\n\n    /* t */\n    vli_set(result, product);\n\n    /* s1 */\n    tmp[0] = 0;\n    tmp[1] = product[5] & 0xffffffff00000000ull;\n    tmp[2] = product[6];\n    tmp[3] = product[7];\n    carry = vli_add(tmp, tmp, tmp);\n    carry += vli_add(result, result, tmp);\n\n    /* s2 */\n    tmp[1] = product[6] << 32;\n    tmp[2] = (product[6] >> 32) | (product[7] << 32);\n    tmp[3] = product[7] >> 32;\n    carry += vli_add(tmp, tmp, tmp);\n    carry += vli_add(result, result, tmp);\n\n    /* s3 */\n    tmp[0] = product[4];\n    tmp[1] = product[5] & 0xffffffff;\n    tmp[2] = 0;\n    tmp[3] = product[7];\n    carry += vli_add(result, result, tmp);\n\n    /* s4 */\n    tmp[0] = (product[4] >> 32) | (product[5] << 32);\n    tmp[1] = (product[5] >> 32) | (product[6] & 0xffffffff00000000ull);\n    tmp[2] = product[7];\n    tmp[3] = (product[6] >> 32) | (product[4] << 32);\n    carry += vli_add(result, result, tmp);\n\n    /* d1 */\n    tmp[0] = (product[5] >> 32) | (product[6] << 32);\n    tmp[1] = (product[6] >> 32);\n    tmp[2] = 0;\n    tmp[3] = (product[4] & 0xffffffff) | (product[5] << 32);\n    carry -= vli_sub(result, result, tmp);\n\n    /* d2 */\n    tmp[0] = product[6];\n    tmp[1] = product[7];\n    tmp[2] = 0;\n    tmp[3] = (product[4] >> 32) | (product[5] & 0xffffffff00000000ull);\n    carry -= vli_sub(result, result, tmp);\n\n    /* d3 */\n    tmp[0] = (product[6] >> 32) | (product[7] << 32);\n    tmp[1] = (product[7] >> 32) | (product[4] << 32);\n    tmp[2] = (product[4] >> 32) | (product[5] << 32);\n    tmp[3] = (product[6] << 32);\n    carry -= vli_sub(result, result, tmp);\n\n    /* d4 */\n    tmp[0] = product[7];\n    tmp[1] = product[4] & 0xffffffff00000000ull;\n    tmp[2] = product[5];\n    tmp[3] = product[6] & 0xffffffff00000000ull;\n    carry -= vli_sub(result, result, tmp);\n\n    if (carry < 0) {\n        do {\n            carry += vli_add(result, result, curve_p);\n        } while (carry < 0);\n    } else {\n        while (carry || vli_cmp(curve_p, result) != 1) {\n            carry -= vli_sub(result, result, curve_p);\n        }\n    }\n}\n#endif /* uECC_WORD_SIZE */\n\n#elif uECC_CURVE == uECC_secp256k1\n\n#if uECC_WORD_SIZE == 1\nstatic void omega_mult(uint8_t * RESTRICT result, const uint8_t * RESTRICT right) {\n    /* Multiply by (2^32 + 2^9 + 2^8 + 2^7 + 2^6 + 2^4 + 1). */\n    uECC_word_t r0 = 0;\n    uECC_word_t r1 = 0;\n    uECC_word_t r2 = 0;\n    wordcount_t k;\n\n    /* Multiply by (2^9 + 2^8 + 2^7 + 2^6 + 2^4 + 1). */\n    muladd(0xD1, right[0], &r0, &r1, &r2);\n    result[0] = r0;\n    r0 = r1;\n    r1 = r2;\n    /* r2 is still 0 */\n\n    for (k = 1; k < uECC_WORDS; ++k) {\n        muladd(0x03, right[k - 1], &r0, &r1, &r2);\n        muladd(0xD1, right[k], &r0, &r1, &r2);\n        result[k] = r0;\n        r0 = r1;\n        r1 = r2;\n        r2 = 0;\n    }\n    muladd(0x03, right[uECC_WORDS - 1], &r0, &r1, &r2);\n    result[uECC_WORDS] = r0;\n    result[uECC_WORDS + 1] = r1;\n\n    result[4 + uECC_WORDS] = vli_add(result + 4, result + 4, right); /* add the 2^32 multiple */\n}\n#elif uECC_WORD_SIZE == 4\nstatic void omega_mult(uint32_t * RESTRICT result, const uint32_t * RESTRICT right) {\n    /* Multiply by (2^9 + 2^8 + 2^7 + 2^6 + 2^4 + 1). */\n    uint32_t carry = 0;\n    wordcount_t k;\n\n    for (k = 0; k < uECC_WORDS; ++k) {\n        uint64_t p = (uint64_t)0x3D1 * right[k] + carry;\n        result[k] = (p & 0xffffffff);\n        carry = p >> 32;\n    }\n    result[uECC_WORDS] = carry;\n\n    result[1 + uECC_WORDS] = vli_add(result + 1, result + 1, right); /* add the 2^32 multiple */\n}\n#else\nstatic void omega_mult(uint64_t * RESTRICT result, const uint64_t * RESTRICT right) {\n    uECC_word_t r0 = 0;\n    uECC_word_t r1 = 0;\n    uECC_word_t r2 = 0;\n    wordcount_t k;\n\n    /* Multiply by (2^32 + 2^9 + 2^8 + 2^7 + 2^6 + 2^4 + 1). */\n    for (k = 0; k < uECC_WORDS; ++k) {\n        muladd(0x1000003D1ull, right[k], &r0, &r1, &r2);\n        result[k] = r0;\n        r0 = r1;\n        r1 = r2;\n        r2 = 0;\n    }\n    result[uECC_WORDS] = r0;\n}\n#endif /* uECC_WORD_SIZE */\n\n#elif uECC_CURVE == uECC_secp224r1\n\n/* Computes result = product % curve_p\n   from http://www.nsa.gov/ia/_files/nist-routines.pdf */\n#if uECC_WORD_SIZE == 1\n// TODO it may be faster to use the omega_mult method when fully asm optimized.\nvoid vli_mmod_fast(uint8_t *RESTRICT result, uint8_t *RESTRICT product) {\n    uint8_t tmp[uECC_WORDS];\n    int8_t carry;\n\n    /* t */\n    vli_set(result, product);\n\n    /* s1 */\n    tmp[0] = tmp[1] = tmp[2] = tmp[3] = 0;\n    tmp[4] = tmp[5] = tmp[6] = tmp[7] = 0;\n    tmp[8] = tmp[9] = tmp[10] = tmp[11] = 0;\n    tmp[12] = product[28]; tmp[13] = product[29]; tmp[14] = product[30]; tmp[15] = product[31];\n    tmp[16] = product[32]; tmp[17] = product[33]; tmp[18] = product[34]; tmp[19] = product[35];\n    tmp[20] = product[36]; tmp[21] = product[37]; tmp[22] = product[38]; tmp[23] = product[39];\n    tmp[24] = product[40]; tmp[25] = product[41]; tmp[26] = product[42]; tmp[27] = product[43];\n    carry = vli_add(result, result, tmp);\n\n    /* s2 */\n    tmp[12] = product[44]; tmp[13] = product[45]; tmp[14] = product[46]; tmp[15] = product[47];\n    tmp[16] = product[48]; tmp[17] = product[49]; tmp[18] = product[50]; tmp[19] = product[51];\n    tmp[20] = product[52]; tmp[21] = product[53]; tmp[22] = product[54]; tmp[23] = product[55];\n    tmp[24] = tmp[25] = tmp[26] = tmp[27] = 0;\n    carry += vli_add(result, result, tmp);\n\n    /* d1 */\n    tmp[0]  = product[28]; tmp[1]  = product[29]; tmp[2]  = product[30]; tmp[3]  = product[31];\n    tmp[4]  = product[32]; tmp[5]  = product[33]; tmp[6]  = product[34]; tmp[7]  = product[35];\n    tmp[8]  = product[36]; tmp[9]  = product[37]; tmp[10] = product[38]; tmp[11] = product[39];\n    tmp[12] = product[40]; tmp[13] = product[41]; tmp[14] = product[42]; tmp[15] = product[43];\n    tmp[16] = product[44]; tmp[17] = product[45]; tmp[18] = product[46]; tmp[19] = product[47];\n    tmp[20] = product[48]; tmp[21] = product[49]; tmp[22] = product[50]; tmp[23] = product[51];\n    tmp[24] = product[52]; tmp[25] = product[53]; tmp[26] = product[54]; tmp[27] = product[55];\n    carry -= vli_sub(result, result, tmp);\n\n    /* d2 */\n    tmp[0]  = product[44]; tmp[1]  = product[45]; tmp[2]  = product[46]; tmp[3]  = product[47];\n    tmp[4]  = product[48]; tmp[5]  = product[49]; tmp[6]  = product[50]; tmp[7]  = product[51];\n    tmp[8]  = product[52]; tmp[9]  = product[53]; tmp[10] = product[54]; tmp[11] = product[55];\n    tmp[12] = tmp[13] = tmp[14] = tmp[15] = 0;\n    tmp[16] = tmp[17] = tmp[18] = tmp[19] = 0;\n    tmp[20] = tmp[21] = tmp[22] = tmp[23] = 0;\n    tmp[24] = tmp[25] = tmp[26] = tmp[27] = 0;\n    carry -= vli_sub(result, result, tmp);\n\n    if (carry < 0) {\n        do {\n            carry += vli_add(result, result, curve_p);\n        } while (carry < 0);\n    } else {\n        while (carry || vli_cmp(curve_p, result) != 1) {\n            carry -= vli_sub(result, result, curve_p);\n        }\n    }\n}\n#elif uECC_WORD_SIZE == 4\nvoid vli_mmod_fast(uint32_t *RESTRICT result, uint32_t *RESTRICT product)\n{\n    uint32_t tmp[uECC_WORDS];\n    int carry;\n\n    /* t */\n    vli_set(result, product);\n\n    /* s1 */\n    tmp[0] = tmp[1] = tmp[2] = 0;\n    tmp[3] = product[7];\n    tmp[4] = product[8];\n    tmp[5] = product[9];\n    tmp[6] = product[10];\n    carry = vli_add(result, result, tmp);\n\n    /* s2 */\n    tmp[3] = product[11];\n    tmp[4] = product[12];\n    tmp[5] = product[13];\n    tmp[6] = 0;\n    carry += vli_add(result, result, tmp);\n\n    /* d1 */\n    tmp[0] = product[7];\n    tmp[1] = product[8];\n    tmp[2] = product[9];\n    tmp[3] = product[10];\n    tmp[4] = product[11];\n    tmp[5] = product[12];\n    tmp[6] = product[13];\n    carry -= vli_sub(result, result, tmp);\n\n    /* d2 */\n    tmp[0] = product[11];\n    tmp[1] = product[12];\n    tmp[2] = product[13];\n    tmp[3] = tmp[4] = tmp[5] = tmp[6] = 0;\n    carry -= vli_sub(result, result, tmp);\n\n    if (carry < 0) {\n        do {\n            carry += vli_add(result, result, curve_p);\n        } while (carry < 0);\n    } else {\n        while (carry || vli_cmp(curve_p, result) != 1) {\n            carry -= vli_sub(result, result, curve_p);\n        }\n    }\n}\n#endif /* uECC_WORD_SIZE */\n\n#endif /* uECC_CURVE */\n#endif /* !asm_mmod_fast */\n\n/* Computes result = (left * right) % curve_p. */\nstatic void vli_modMult_fast(uECC_word_t *result,\n                             const uECC_word_t *left,\n                             const uECC_word_t *right) {\n    uECC_word_t product[2 * uECC_WORDS];\n    vli_mult(product, left, right);\n    vli_mmod_fast(result, product);\n}\n\n#if uECC_SQUARE_FUNC\n\n/* Computes result = left^2 % curve_p. */\nstatic void vli_modSquare_fast(uECC_word_t *result, const uECC_word_t *left) {\n    uECC_word_t product[2 * uECC_WORDS];\n    vli_square(product, left);\n    vli_mmod_fast(result, product);\n}\n\n#else /* uECC_SQUARE_FUNC */\n\n#define vli_modSquare_fast(result, left) vli_modMult_fast((result), (left), (left))\n\n#endif /* uECC_SQUARE_FUNC */\n\n\n#define EVEN(vli) (!(vli[0] & 1))\n/* Computes result = (1 / input) % mod. All VLIs are the same size.\n   See \"From Euclid's GCD to Montgomery Multiplication to the Great Divide\"\n   https://labs.oracle.com/techrep/2001/smli_tr-2001-95.pdf */\n#if !asm_modInv\nstatic void vli_modInv(uECC_word_t *result, const uECC_word_t *input, const uECC_word_t *mod) {\n    uECC_word_t a[uECC_WORDS], b[uECC_WORDS], u[uECC_WORDS], v[uECC_WORDS];\n    uECC_word_t carry;\n    cmpresult_t cmpResult;\n\n    if (vli_isZero(input)) {\n        vli_clear(result);\n        return;\n    }\n\n    vli_set(a, input);\n    vli_set(b, mod);\n    vli_clear(u);\n    u[0] = 1;\n    vli_clear(v);\n    while ((cmpResult = vli_cmp(a, b)) != 0) {\n        carry = 0;\n        if (EVEN(a)) {\n            vli_rshift1(a);\n            if (!EVEN(u)) {\n                carry = vli_add(u, u, mod);\n            }\n            vli_rshift1(u);\n            if (carry) {\n                u[uECC_WORDS - 1] |= HIGH_BIT_SET;\n            }\n        } else if (EVEN(b)) {\n            vli_rshift1(b);\n            if (!EVEN(v)) {\n                carry = vli_add(v, v, mod);\n            }\n            vli_rshift1(v);\n            if (carry) {\n                v[uECC_WORDS - 1] |= HIGH_BIT_SET;\n            }\n        } else if (cmpResult > 0) {\n            vli_sub(a, a, b);\n            vli_rshift1(a);\n            if (vli_cmp(u, v) < 0) {\n                vli_add(u, u, mod);\n            }\n            vli_sub(u, u, v);\n            if (!EVEN(u)) {\n                carry = vli_add(u, u, mod);\n            }\n            vli_rshift1(u);\n            if (carry) {\n                u[uECC_WORDS - 1] |= HIGH_BIT_SET;\n            }\n        } else {\n            vli_sub(b, b, a);\n            vli_rshift1(b);\n            if (vli_cmp(v, u) < 0) {\n                vli_add(v, v, mod);\n            }\n            vli_sub(v, v, u);\n            if (!EVEN(v)) {\n                carry = vli_add(v, v, mod);\n            }\n            vli_rshift1(v);\n            if (carry) {\n                v[uECC_WORDS - 1] |= HIGH_BIT_SET;\n            }\n        }\n    }\n    vli_set(result, u);\n}\n#endif /* !asm_modInv */\n\n/* ------ Point operations ------ */\n\n/* Returns 1 if 'point' is the point at infinity, 0 otherwise. */\nstatic cmpresult_t EccPoint_isZero(const EccPoint *point) {\n    return (vli_isZero(point->x) && vli_isZero(point->y));\n}\n\n/* Point multiplication algorithm using Montgomery's ladder with co-Z coordinates.\nFrom http://eprint.iacr.org/2011/338.pdf\n*/\n\n/* Double in place */\n#if (uECC_CURVE == uECC_secp256k1)\nstatic void EccPoint_double_jacobian(uECC_word_t * RESTRICT X1,\n                                     uECC_word_t * RESTRICT Y1,\n                                     uECC_word_t * RESTRICT Z1) {\n    /* t1 = X, t2 = Y, t3 = Z */\n    uECC_word_t t4[uECC_WORDS];\n    uECC_word_t t5[uECC_WORDS];\n\n    if (vli_isZero(Z1)) {\n        return;\n    }\n\n    vli_modSquare_fast(t5, Y1);   /* t5 = y1^2 */\n    vli_modMult_fast(t4, X1, t5); /* t4 = x1*y1^2 = A */\n    vli_modSquare_fast(X1, X1);   /* t1 = x1^2 */\n    vli_modSquare_fast(t5, t5);   /* t5 = y1^4 */\n    vli_modMult_fast(Z1, Y1, Z1); /* t3 = y1*z1 = z3 */\n\n    vli_modAdd(Y1, X1, X1, curve_p); /* t2 = 2*x1^2 */\n    vli_modAdd(Y1, Y1, X1, curve_p); /* t2 = 3*x1^2 */\n    if (vli_testBit(Y1, 0)) {\n        uECC_word_t carry = vli_add(Y1, Y1, curve_p);\n        vli_rshift1(Y1);\n        Y1[uECC_WORDS - 1] |= carry << (uECC_WORD_BITS - 1);\n    } else {\n        vli_rshift1(Y1);\n    }\n    /* t2 = 3/2*(x1^2) = B */\n\n    vli_modSquare_fast(X1, Y1);      /* t1 = B^2 */\n    vli_modSub(X1, X1, t4, curve_p); /* t1 = B^2 - A */\n    vli_modSub(X1, X1, t4, curve_p); /* t1 = B^2 - 2A = x3 */\n\n    vli_modSub(t4, t4, X1, curve_p); /* t4 = A - x3 */\n    vli_modMult_fast(Y1, Y1, t4);    /* t2 = B * (A - x3) */\n    vli_modSub(Y1, Y1, t5, curve_p); /* t2 = B * (A - x3) - y1^4 = y3 */\n}\n#else\nstatic void EccPoint_double_jacobian(uECC_word_t * RESTRICT X1,\n                                     uECC_word_t * RESTRICT Y1,\n                                     uECC_word_t * RESTRICT Z1) {\n    /* t1 = X, t2 = Y, t3 = Z */\n    uECC_word_t t4[uECC_WORDS];\n    uECC_word_t t5[uECC_WORDS];\n\n    if (vli_isZero(Z1)) {\n        return;\n    }\n\n    vli_modSquare_fast(t4, Y1);   /* t4 = y1^2 */\n    vli_modMult_fast(t5, X1, t4); /* t5 = x1*y1^2 = A */\n    vli_modSquare_fast(t4, t4);   /* t4 = y1^4 */\n    vli_modMult_fast(Y1, Y1, Z1); /* t2 = y1*z1 = z3 */\n    vli_modSquare_fast(Z1, Z1);   /* t3 = z1^2 */\n\n    vli_modAdd(X1, X1, Z1, curve_p); /* t1 = x1 + z1^2 */\n    vli_modAdd(Z1, Z1, Z1, curve_p); /* t3 = 2*z1^2 */\n    vli_modSub_fast(Z1, X1, Z1);     /* t3 = x1 - z1^2 */\n    vli_modMult_fast(X1, X1, Z1);    /* t1 = x1^2 - z1^4 */\n\n    vli_modAdd(Z1, X1, X1, curve_p); /* t3 = 2*(x1^2 - z1^4) */\n    vli_modAdd(X1, X1, Z1, curve_p); /* t1 = 3*(x1^2 - z1^4) */\n    if (vli_testBit(X1, 0)) {\n        uECC_word_t l_carry = vli_add(X1, X1, curve_p);\n        vli_rshift1(X1);\n        X1[uECC_WORDS - 1] |= l_carry << (uECC_WORD_BITS - 1);\n    } else {\n        vli_rshift1(X1);\n    }\n    /* t1 = 3/2*(x1^2 - z1^4) = B */\n\n    vli_modSquare_fast(Z1, X1);   /* t3 = B^2 */\n    vli_modSub_fast(Z1, Z1, t5);  /* t3 = B^2 - A */\n    vli_modSub_fast(Z1, Z1, t5);  /* t3 = B^2 - 2A = x3 */\n    vli_modSub_fast(t5, t5, Z1);  /* t5 = A - x3 */\n    vli_modMult_fast(X1, X1, t5); /* t1 = B * (A - x3) */\n    vli_modSub_fast(t4, X1, t4);  /* t4 = B * (A - x3) - y1^4 = y3 */\n\n    vli_set(X1, Z1);\n    vli_set(Z1, Y1);\n    vli_set(Y1, t4);\n}\n#endif\n\n/* Modify (x1, y1) => (x1 * z^2, y1 * z^3) */\nstatic void apply_z(uECC_word_t * RESTRICT X1,\n                    uECC_word_t * RESTRICT Y1,\n                    const uECC_word_t * RESTRICT Z) {\n    uECC_word_t t1[uECC_WORDS];\n\n    vli_modSquare_fast(t1, Z);    /* z^2 */\n    vli_modMult_fast(X1, X1, t1); /* x1 * z^2 */\n    vli_modMult_fast(t1, t1, Z);  /* z^3 */\n    vli_modMult_fast(Y1, Y1, t1); /* y1 * z^3 */\n}\n\n/* P = (x1, y1) => 2P, (x2, y2) => P' */\nstatic void XYcZ_initial_double(uECC_word_t * RESTRICT X1,\n                                uECC_word_t * RESTRICT Y1,\n                                uECC_word_t * RESTRICT X2,\n                                uECC_word_t * RESTRICT Y2,\n                                const uECC_word_t * RESTRICT initial_Z) {\n    uECC_word_t z[uECC_WORDS];\n    if (initial_Z) {\n        vli_set(z, initial_Z);\n    } else {\n        vli_clear(z);\n        z[0] = 1;\n    }\n\n    vli_set(X2, X1);\n    vli_set(Y2, Y1);\n\n    apply_z(X1, Y1, z);\n    EccPoint_double_jacobian(X1, Y1, z);\n    apply_z(X2, Y2, z);\n}\n\n/* Input P = (x1, y1, Z), Q = (x2, y2, Z)\n   Output P' = (x1', y1', Z3), P + Q = (x3, y3, Z3)\n   or P => P', Q => P + Q\n*/\nstatic void XYcZ_add(uECC_word_t * RESTRICT X1,\n                     uECC_word_t * RESTRICT Y1,\n                     uECC_word_t * RESTRICT X2,\n                     uECC_word_t * RESTRICT Y2) {\n    /* t1 = X1, t2 = Y1, t3 = X2, t4 = Y2 */\n    uECC_word_t t5[uECC_WORDS];\n\n    vli_modSub_fast(t5, X2, X1);  /* t5 = x2 - x1 */\n    vli_modSquare_fast(t5, t5);   /* t5 = (x2 - x1)^2 = A */\n    vli_modMult_fast(X1, X1, t5); /* t1 = x1*A = B */\n    vli_modMult_fast(X2, X2, t5); /* t3 = x2*A = C */\n    vli_modSub_fast(Y2, Y2, Y1);  /* t4 = y2 - y1 */\n    vli_modSquare_fast(t5, Y2);   /* t5 = (y2 - y1)^2 = D */\n\n    vli_modSub_fast(t5, t5, X1);  /* t5 = D - B */\n    vli_modSub_fast(t5, t5, X2);  /* t5 = D - B - C = x3 */\n    vli_modSub_fast(X2, X2, X1);  /* t3 = C - B */\n    vli_modMult_fast(Y1, Y1, X2); /* t2 = y1*(C - B) */\n    vli_modSub_fast(X2, X1, t5);  /* t3 = B - x3 */\n    vli_modMult_fast(Y2, Y2, X2); /* t4 = (y2 - y1)*(B - x3) */\n    vli_modSub_fast(Y2, Y2, Y1);  /* t4 = y3 */\n\n    vli_set(X2, t5);\n}\n\n/* Input P = (x1, y1, Z), Q = (x2, y2, Z)\n   Output P + Q = (x3, y3, Z3), P - Q = (x3', y3', Z3)\n   or P => P - Q, Q => P + Q\n*/\nstatic void XYcZ_addC(uECC_word_t * RESTRICT X1,\n                      uECC_word_t * RESTRICT Y1,\n                      uECC_word_t * RESTRICT X2,\n                      uECC_word_t * RESTRICT Y2) {\n    /* t1 = X1, t2 = Y1, t3 = X2, t4 = Y2 */\n    uECC_word_t t5[uECC_WORDS];\n    uECC_word_t t6[uECC_WORDS];\n    uECC_word_t t7[uECC_WORDS];\n\n    vli_modSub_fast(t5, X2, X1);     /* t5 = x2 - x1 */\n    vli_modSquare_fast(t5, t5);      /* t5 = (x2 - x1)^2 = A */\n    vli_modMult_fast(X1, X1, t5);    /* t1 = x1*A = B */\n    vli_modMult_fast(X2, X2, t5);    /* t3 = x2*A = C */\n    vli_modAdd(t5, Y2, Y1, curve_p); /* t5 = y2 + y1 */\n    vli_modSub_fast(Y2, Y2, Y1);     /* t4 = y2 - y1 */\n\n    vli_modSub_fast(t6, X2, X1);     /* t6 = C - B */\n    vli_modMult_fast(Y1, Y1, t6);    /* t2 = y1 * (C - B) = E */\n    vli_modAdd(t6, X1, X2, curve_p); /* t6 = B + C */\n    vli_modSquare_fast(X2, Y2);      /* t3 = (y2 - y1)^2 = D */\n    vli_modSub_fast(X2, X2, t6);     /* t3 = D - (B + C) = x3 */\n\n    vli_modSub_fast(t7, X1, X2);  /* t7 = B - x3 */\n    vli_modMult_fast(Y2, Y2, t7); /* t4 = (y2 - y1)*(B - x3) */\n    vli_modSub_fast(Y2, Y2, Y1);  /* t4 = (y2 - y1)*(B - x3) - E = y3 */\n\n    vli_modSquare_fast(t7, t5);   /* t7 = (y2 + y1)^2 = F */\n    vli_modSub_fast(t7, t7, t6);  /* t7 = F - (B + C) = x3' */\n    vli_modSub_fast(t6, t7, X1);  /* t6 = x3' - B */\n    vli_modMult_fast(t6, t6, t5); /* t6 = (y2 + y1)*(x3' - B) */\n    vli_modSub_fast(Y1, t6, Y1);  /* t2 = (y2 + y1)*(x3' - B) - E = y3' */\n\n    vli_set(X1, t7);\n}\n\nstatic void EccPoint_mult(EccPoint * RESTRICT result,\n                          const EccPoint * RESTRICT point,\n                          const uECC_word_t * RESTRICT scalar,\n                          const uECC_word_t * RESTRICT initialZ,\n                          bitcount_t numBits) {\n    /* R0 and R1 */\n    uECC_word_t Rx[2][uECC_WORDS];\n    uECC_word_t Ry[2][uECC_WORDS];\n    uECC_word_t z[uECC_WORDS];\n    bitcount_t i;\n    uECC_word_t nb;\n\n    vli_set(Rx[1], point->x);\n    vli_set(Ry[1], point->y);\n\n    XYcZ_initial_double(Rx[1], Ry[1], Rx[0], Ry[0], initialZ);\n\n    for (i = numBits - 2; i > 0; --i) {\n        nb = !vli_testBit(scalar, i);\n        XYcZ_addC(Rx[1 - nb], Ry[1 - nb], Rx[nb], Ry[nb]);\n        XYcZ_add(Rx[nb], Ry[nb], Rx[1 - nb], Ry[1 - nb]);\n    }\n\n    nb = !vli_testBit(scalar, 0);\n    XYcZ_addC(Rx[1 - nb], Ry[1 - nb], Rx[nb], Ry[nb]);\n\n    /* Find final 1/Z value. */\n    vli_modSub_fast(z, Rx[1], Rx[0]);   /* X1 - X0 */\n    vli_modMult_fast(z, z, Ry[1 - nb]); /* Yb * (X1 - X0) */\n    vli_modMult_fast(z, z, point->x); /* xP * Yb * (X1 - X0) */\n    vli_modInv(z, z, curve_p);          /* 1 / (xP * Yb * (X1 - X0)) */\n    vli_modMult_fast(z, z, point->y); /* yP / (xP * Yb * (X1 - X0)) */\n    vli_modMult_fast(z, z, Rx[1 - nb]); /* Xb * yP / (xP * Yb * (X1 - X0)) */\n    /* End 1/Z calculation */\n\n    XYcZ_add(Rx[nb], Ry[nb], Rx[1 - nb], Ry[1 - nb]);\n    apply_z(Rx[0], Ry[0], z);\n\n    vli_set(result->x, Rx[0]);\n    vli_set(result->y, Ry[0]);\n}\n\nstatic int EccPoint_compute_public_key(EccPoint *result, uECC_word_t *private) {\n    uECC_word_t tmp1[uECC_WORDS];\n    uECC_word_t tmp2[uECC_WORDS];\n    uECC_word_t *p2[2] = {tmp1, tmp2};\n    uECC_word_t carry;\n\n    /* Make sure the private key is in the range [1, n-1]. */\n    if (vli_isZero(private)) {\n        return 0;\n    }\n\n#if (uECC_CURVE == uECC_secp160r1)\n    // Don't regularize the bitcount for secp160r1, since it would have a larger performance\n    // impact (about 2% slower on average) and requires the vli_xxx_n functions, leading to\n    // a significant increase in code size.\n\n    EccPoint_mult(result, &curve_G, private, 0, vli_numBits(private, uECC_WORDS));\n#else\n    if (vli_cmp(curve_n, private) != 1) {\n        return 0;\n    }\n\n    // Regularize the bitcount for the private key so that attackers cannot use a side channel\n    // attack to learn the number of leading zeros.\n    carry = vli_add(tmp1, private, curve_n);\n    vli_add(tmp2, tmp1, curve_n);\n    EccPoint_mult(result, &curve_G, p2[!carry], 0, (uECC_BYTES * 8) + 1);\n#endif\n\n    if (EccPoint_isZero(result)) {\n        return 0;\n    }\n    return 1;\n}\n\n#if uECC_CURVE == uECC_secp224r1\n\n/* Routine 3.2.4 RS;  from http://www.nsa.gov/ia/_files/nist-routines.pdf */\nstatic void mod_sqrt_secp224r1_rs(uECC_word_t *d1,\n                                  uECC_word_t *e1,\n                                  uECC_word_t *f1,\n                                  const uECC_word_t *d0,\n                                  const uECC_word_t *e0,\n                                  const uECC_word_t *f0) {\n    uECC_word_t t[uECC_WORDS];\n\n    vli_modSquare_fast(t, d0);                 /* t <-- d0 ^ 2 */\n    vli_modMult_fast(e1, d0, e0);              /* e1 <-- d0 * e0 */\n    vli_modAdd(d1, t, f0, curve_p);            /* d1 <-- t  + f0 */\n    vli_modAdd(e1, e1, e1, curve_p);           /* e1 <-- e1 + e1 */\n    vli_modMult_fast(f1, t, f0);               /* f1 <-- t  * f0 */\n    vli_modAdd(f1, f1, f1, curve_p);           /* f1 <-- f1 + f1 */\n    vli_modAdd(f1, f1, f1, curve_p);           /* f1 <-- f1 + f1 */\n}\n\n/* Routine 3.2.5 RSS;  from http://www.nsa.gov/ia/_files/nist-routines.pdf */\nstatic void mod_sqrt_secp224r1_rss(uECC_word_t *d1,\n                                   uECC_word_t *e1,\n                                   uECC_word_t *f1,\n                                   const uECC_word_t *d0,\n                                   const uECC_word_t *e0,\n                                   const uECC_word_t *f0,\n                                   const bitcount_t j) {\n    bitcount_t i;\n\n    vli_set(d1, d0);                           /* d1 <-- d0 */\n    vli_set(e1, e0);                           /* e1 <-- e0 */\n    vli_set(f1, f0);                           /* f1 <-- f0 */\n    for (i = 1; i <= j; i++) {\n        mod_sqrt_secp224r1_rs(d1, e1, f1, d1, e1, f1); /* RS (d1,e1,f1,d1,e1,f1) */\n    }\n}\n\n/* Routine 3.2.6 RM;  from http://www.nsa.gov/ia/_files/nist-routines.pdf */\nstatic void mod_sqrt_secp224r1_rm(uECC_word_t *d2,\n                                  uECC_word_t *e2,\n                                  uECC_word_t *f2,\n                                  const uECC_word_t *c,\n                                  const uECC_word_t *d0,\n                                  const uECC_word_t *e0,\n                                  const uECC_word_t *d1,\n                                  const uECC_word_t *e1) {\n    uECC_word_t t1[uECC_WORDS];\n    uECC_word_t t2[uECC_WORDS];\n\n    vli_modMult_fast(t1, e0, e1);              /* t1 <-- e0 * e1 */\n    vli_modMult_fast(t1, t1, c);               /* t1 <-- t1 * c */\n    vli_modSub_fast(t1, curve_p, t1);          /* t1 <-- p  - t1 */\n    vli_modMult_fast(t2, d0, d1);              /* t2 <-- d0 * d1 */\n    vli_modAdd(t2, t2, t1, curve_p);           /* t2 <-- t2 + t1 */\n    vli_modMult_fast(t1, d0, e1);              /* t1 <-- d0 * e1 */\n    vli_modMult_fast(e2, d1, e0);              /* e2 <-- d1 * e0 */\n    vli_modAdd(e2, e2, t1, curve_p);           /* e2 <-- e2 + t1 */\n    vli_modSquare_fast(f2, e2);                /* f2 <-- e2^2 */\n    vli_modMult_fast(f2, f2, c);               /* f2 <-- f2 * c */\n    vli_modSub_fast(f2, curve_p, f2);          /* f2 <-- p  - f2 */\n    vli_set(d2, t2);                           /* d2 <-- t2 */\n}\n\n/* Routine 3.2.7 RP;  from http://www.nsa.gov/ia/_files/nist-routines.pdf */\nstatic void mod_sqrt_secp224r1_rp(uECC_word_t *d1,\n                                  uECC_word_t *e1,\n                                  uECC_word_t *f1,\n                                  const uECC_word_t *c,\n                                  const uECC_word_t *r) {\n    wordcount_t i;\n    wordcount_t pow2i = 1;\n    uECC_word_t d0[uECC_WORDS];\n    uECC_word_t e0[uECC_WORDS] = {1};          /* e0 <-- 1 */\n    uECC_word_t f0[uECC_WORDS];\n\n    vli_set(d0, r);                            /* d0 <-- r */\n    vli_modSub_fast(f0, curve_p, c);           /* f0 <-- p  - c */\n    for (i = 0; i <= 6; i++) {\n        mod_sqrt_secp224r1_rss(d1, e1, f1, d0, e0, f0, pow2i); /* RSS (d1,e1,f1,d0,e0,f0,2^i) */\n        mod_sqrt_secp224r1_rm(d1, e1, f1, c, d1, e1, d0, e0);  /* RM (d1,e1,f1,c,d1,e1,d0,e0) */\n        vli_set(d0, d1);                       /* d0 <-- d1 */\n        vli_set(e0, e1);                       /* e0 <-- e1 */\n        vli_set(f0, f1);                       /* f0 <-- f1 */\n        pow2i *= 2;\n    }\n}\n\n/* Compute a = sqrt(a) (mod curve_p). */\n/* Routine 3.2.8 mp_mod_sqrt_224; from http://www.nsa.gov/ia/_files/nist-routines.pdf */\nstatic void mod_sqrt(uECC_word_t *a) {\n    bitcount_t i;\n    uECC_word_t e1[uECC_WORDS];\n    uECC_word_t f1[uECC_WORDS];\n    uECC_word_t d0[uECC_WORDS];\n    uECC_word_t e0[uECC_WORDS];\n    uECC_word_t f0[uECC_WORDS];\n    uECC_word_t d1[uECC_WORDS];\n\n    // s = a; using constant instead of random value\n    mod_sqrt_secp224r1_rp(d0, e0, f0, a, a);           /* RP (d0, e0, f0, c, s) */\n    mod_sqrt_secp224r1_rs(d1, e1, f1, d0, e0, f0);     /* RS (d1, e1, f1, d0, e0, f0) */\n    for (i = 1; i <= 95; i++) {\n        vli_set(d0, d1);                               /* d0 <-- d1 */\n        vli_set(e0, e1);                               /* e0 <-- e1 */\n        vli_set(f0, f1);                               /* f0 <-- f1 */\n        mod_sqrt_secp224r1_rs(d1, e1, f1, d0, e0, f0); /* RS (d1, e1, f1, d0, e0, f0) */\n        if (vli_isZero(d1)) {                          /* if d1 == 0 */\n\t        break;\n        }\n    }\n    vli_modInv(f1, e0, curve_p);                       /* f1 <-- 1 / e0 */\n    vli_modMult_fast(a, d0, f1);                       /* a  <-- d0 / e0 */\n}\n\n#else /* uECC_CURVE */\n\n/* Compute a = sqrt(a) (mod curve_p). */\nstatic void mod_sqrt(uECC_word_t *a) {\n    bitcount_t i;\n    uECC_word_t p1[uECC_WORDS] = {1};\n    uECC_word_t l_result[uECC_WORDS] = {1};\n\n    /* Since curve_p == 3 (mod 4) for all supported curves, we can\n       compute sqrt(a) = a^((curve_p + 1) / 4) (mod curve_p). */\n    vli_add(p1, curve_p, p1); /* p1 = curve_p + 1 */\n    for (i = vli_numBits(p1, uECC_WORDS) - 1; i > 1; --i) {\n        vli_modSquare_fast(l_result, l_result);\n        if (vli_testBit(p1, i)) {\n            vli_modMult_fast(l_result, l_result, a);\n        }\n    }\n    vli_set(a, l_result);\n}\n#endif /* uECC_CURVE */\n\n#if uECC_WORD_SIZE == 1\n\nstatic void vli_nativeToBytes(uint8_t * RESTRICT dest, const uint8_t * RESTRICT src) {\n    uint8_t i;\n    for (i = 0; i < uECC_BYTES; ++i) {\n        dest[i] = src[(uECC_BYTES - 1) - i];\n    }\n}\n\n#define vli_bytesToNative(dest, src) vli_nativeToBytes((dest), (src))\n\n#elif uECC_WORD_SIZE == 4\n\nstatic void vli_nativeToBytes(uint8_t *bytes, const uint32_t *native) {\n    unsigned i;\n    for (i = 0; i < uECC_WORDS; ++i) {\n        uint8_t *digit = bytes + 4 * (uECC_WORDS - 1 - i);\n        digit[0] = native[i] >> 24;\n        digit[1] = native[i] >> 16;\n        digit[2] = native[i] >> 8;\n        digit[3] = native[i];\n    }\n}\n\nstatic void vli_bytesToNative(uint32_t *native, const uint8_t *bytes) {\n    unsigned i;\n    for (i = 0; i < uECC_WORDS; ++i) {\n        const uint8_t *digit = bytes + 4 * (uECC_WORDS - 1 - i);\n        native[i] = ((uint32_t)digit[0] << 24) | ((uint32_t)digit[1] << 16) |\n                    ((uint32_t)digit[2] << 8) | (uint32_t)digit[3];\n    }\n}\n\n#else\n\nstatic void vli_nativeToBytes(uint8_t *bytes, const uint64_t *native) {\n    unsigned i;\n    for (i = 0; i < uECC_WORDS; ++i) {\n        uint8_t *digit = bytes + 8 * (uECC_WORDS - 1 - i);\n        digit[0] = native[i] >> 56;\n        digit[1] = native[i] >> 48;\n        digit[2] = native[i] >> 40;\n        digit[3] = native[i] >> 32;\n        digit[4] = native[i] >> 24;\n        digit[5] = native[i] >> 16;\n        digit[6] = native[i] >> 8;\n        digit[7] = native[i];\n    }\n}\n\nstatic void vli_bytesToNative(uint64_t *native, const uint8_t *bytes) {\n    unsigned i;\n    for (i = 0; i < uECC_WORDS; ++i) {\n        const uint8_t *digit = bytes + 8 * (uECC_WORDS - 1 - i);\n        native[i] = ((uint64_t)digit[0] << 56) | ((uint64_t)digit[1] << 48) |\n                    ((uint64_t)digit[2] << 40) | ((uint64_t)digit[3] << 32) |\n                    ((uint64_t)digit[4] << 24) | ((uint64_t)digit[5] << 16) |\n                    ((uint64_t)digit[6] << 8) | (uint64_t)digit[7];\n    }\n}\n\n#endif /* uECC_WORD_SIZE */\n\nint uECC_make_key(uint8_t public_key[uECC_BYTES*2], uint8_t private_key[uECC_BYTES]) {\n    uECC_word_t private[uECC_WORDS];\n    EccPoint public;\n    uECC_word_t tries;\n    for (tries = 0; tries < MAX_TRIES; ++tries) {\n        if (g_rng_function((uint8_t *)private, sizeof(private)) &&\n                EccPoint_compute_public_key(&public, private)) {\n            vli_nativeToBytes(private_key, private);\n            vli_nativeToBytes(public_key, public.x);\n            vli_nativeToBytes(public_key + uECC_BYTES, public.y);\n            return 1;\n        }\n    }\n    return 0;\n}\n\nint uECC_shared_secret(const uint8_t public_key[uECC_BYTES*2],\n                       const uint8_t private_key[uECC_BYTES],\n                       uint8_t secret[uECC_BYTES]) {\n    EccPoint public;\n    EccPoint product;\n    uECC_word_t private[uECC_WORDS];\n    uECC_word_t tmp[uECC_WORDS];\n    uECC_word_t *p2[2] = {private, tmp};\n    uECC_word_t random[uECC_WORDS];\n    uECC_word_t *initial_Z = 0;\n    uECC_word_t tries;\n    uECC_word_t carry;\n\n    // Try to get a random initial Z value to improve protection against side-channel\n    // attacks. If the RNG fails every time (eg it was not defined), we continue so that\n    // uECC_shared_secret() can still work without an RNG defined.\n    for (tries = 0; tries < MAX_TRIES; ++tries) {\n        if (g_rng_function((uint8_t *)random, sizeof(random)) && !vli_isZero(random)) {\n            initial_Z = random;\n            break;\n        }\n    }\n\n    vli_bytesToNative(private, private_key);\n    vli_bytesToNative(public.x, public_key);\n    vli_bytesToNative(public.y, public_key + uECC_BYTES);\n\n#if (uECC_CURVE == uECC_secp160r1)\n    // Don't regularize the bitcount for secp160r1.\n    EccPoint_mult(&product, &public, private, initial_Z, vli_numBits(private, uECC_WORDS));\n#else\n    // Regularize the bitcount for the private key so that attackers cannot use a side channel\n    // attack to learn the number of leading zeros.\n    carry = vli_add(private, private, curve_n);\n    vli_add(tmp, private, curve_n);\n    EccPoint_mult(&product, &public, p2[!carry], initial_Z, (uECC_BYTES * 8) + 1);\n#endif\n\n    vli_nativeToBytes(secret, product.x);\n    return !EccPoint_isZero(&product);\n}\n\nvoid uECC_compress(const uint8_t public_key[uECC_BYTES*2], uint8_t compressed[uECC_BYTES+1]) {\n    wordcount_t i;\n    for (i = 0; i < uECC_BYTES; ++i) {\n        compressed[i+1] = public_key[i];\n    }\n    compressed[0] = 2 + (public_key[uECC_BYTES * 2 - 1] & 0x01);\n}\n\n/* Computes result = x^3 + ax + b. result must not overlap x. */\nstatic void curve_x_side(uECC_word_t * RESTRICT result, const uECC_word_t * RESTRICT x) {\n#if (uECC_CURVE == uECC_secp256k1)\n    vli_modSquare_fast(result, x); /* r = x^2 */\n    vli_modMult_fast(result, result, x); /* r = x^3 */\n    vli_modAdd(result, result, curve_b, curve_p); /* r = x^3 + b */\n#else\n    uECC_word_t _3[uECC_WORDS] = {3}; /* -a = 3 */\n\n    vli_modSquare_fast(result, x); /* r = x^2 */\n    vli_modSub_fast(result, result, _3); /* r = x^2 - 3 */\n    vli_modMult_fast(result, result, x); /* r = x^3 - 3x */\n    vli_modAdd(result, result, curve_b, curve_p); /* r = x^3 - 3x + b */\n#endif\n}\n\nvoid uECC_decompress(const uint8_t compressed[uECC_BYTES+1], uint8_t public_key[uECC_BYTES*2]) {\n    EccPoint point;\n    vli_bytesToNative(point.x, compressed + 1);\n    curve_x_side(point.y, point.x);\n    mod_sqrt(point.y);\n\n    if ((point.y[0] & 0x01) != (compressed[0] & 0x01)) {\n        vli_sub(point.y, curve_p, point.y);\n    }\n\n    vli_nativeToBytes(public_key, point.x);\n    vli_nativeToBytes(public_key + uECC_BYTES, point.y);\n}\n\nint uECC_valid_public_key(const uint8_t public_key[uECC_BYTES*2]) {\n    uECC_word_t tmp1[uECC_WORDS];\n    uECC_word_t tmp2[uECC_WORDS];\n    EccPoint public;\n\n    vli_bytesToNative(public.x, public_key);\n    vli_bytesToNative(public.y, public_key + uECC_BYTES);\n\n    // The point at infinity is invalid.\n    if (EccPoint_isZero(&public)) {\n        return 0;\n    }\n\n    // x and y must be smaller than p.\n    if (vli_cmp(curve_p, public.x) != 1 || vli_cmp(curve_p, public.y) != 1) {\n        return 0;\n    }\n\n    vli_modSquare_fast(tmp1, public.y); /* tmp1 = y^2 */\n    curve_x_side(tmp2, public.x); /* tmp2 = x^3 + ax + b */\n\n    /* Make sure that y^2 == x^3 + ax + b */\n    return (vli_cmp(tmp1, tmp2) == 0);\n}\n\nint uECC_compute_public_key(const uint8_t private_key[uECC_BYTES],\n                            uint8_t public_key[uECC_BYTES * 2]) {\n    uECC_word_t private[uECC_WORDS];\n    EccPoint public;\n\n    vli_bytesToNative(private, private_key);\n\n    if (!EccPoint_compute_public_key(&public, private)) {\n        return 0;\n    }\n\n    vli_nativeToBytes(public_key, public.x);\n    vli_nativeToBytes(public_key + uECC_BYTES, public.y);\n    return 1;\n}\n\nint uECC_bytes(void) {\n    return uECC_BYTES;\n}\n\nint uECC_curve(void) {\n    return uECC_CURVE;\n}\n\n/* -------- ECDSA code -------- */\n\n#if (uECC_CURVE == uECC_secp160r1)\nstatic void vli_clear_n(uECC_word_t *vli) {\n    vli_clear(vli);\n    vli[uECC_N_WORDS - 1] = 0;\n}\n\nstatic uECC_word_t vli_isZero_n(const uECC_word_t *vli) {\n    if (vli[uECC_N_WORDS - 1]) {\n        return 0;\n    }\n    return vli_isZero(vli);\n}\n\nstatic void vli_set_n(uECC_word_t *dest, const uECC_word_t *src) {\n    vli_set(dest, src);\n    dest[uECC_N_WORDS - 1] = src[uECC_N_WORDS - 1];\n}\n\nstatic cmpresult_t vli_cmp_n(const uECC_word_t *left, const uECC_word_t *right) {\n    if (left[uECC_N_WORDS - 1] > right[uECC_N_WORDS - 1]) {\n        return 1;\n    } else if (left[uECC_N_WORDS - 1] < right[uECC_N_WORDS - 1]) {\n        return -1;\n    }\n    return vli_cmp(left, right);\n}\n\nstatic void vli_rshift1_n(uECC_word_t *vli) {\n    vli_rshift1(vli);\n    vli[uECC_N_WORDS - 2] |= vli[uECC_N_WORDS - 1] << (uECC_WORD_BITS - 1);\n    vli[uECC_N_WORDS - 1] = vli[uECC_N_WORDS - 1] >> 1;\n}\n\nstatic uECC_word_t vli_add_n(uECC_word_t *result,\n                             const uECC_word_t *left,\n                             const uECC_word_t *right) {\n    uECC_word_t carry = vli_add(result, left, right);\n    uECC_word_t sum = left[uECC_N_WORDS - 1] + right[uECC_N_WORDS - 1] + carry;\n    if (sum != left[uECC_N_WORDS - 1]) {\n        carry = (sum < left[uECC_N_WORDS - 1]);\n    }\n    result[uECC_N_WORDS - 1] = sum;\n    return carry;\n}\n\nstatic uECC_word_t vli_sub_n(uECC_word_t *result,\n                             const uECC_word_t *left,\n                             const uECC_word_t *right) {\n    uECC_word_t borrow = vli_sub(result, left, right);\n    uECC_word_t diff = left[uECC_N_WORDS - 1] - right[uECC_N_WORDS - 1] - borrow;\n    if (diff != left[uECC_N_WORDS - 1]) {\n        borrow = (diff > left[uECC_N_WORDS - 1]);\n    }\n    result[uECC_N_WORDS - 1] = diff;\n    return borrow;\n}\n\n#if !muladd_exists\nstatic void muladd(uECC_word_t a,\n                   uECC_word_t b,\n                   uECC_word_t *r0,\n                   uECC_word_t *r1,\n                   uECC_word_t *r2) {\n    uECC_dword_t p = (uECC_dword_t)a * b;\n    uECC_dword_t r01 = ((uECC_dword_t)(*r1) << uECC_WORD_BITS) | *r0;\n    r01 += p;\n    *r2 += (r01 < p);\n    *r1 = r01 >> uECC_WORD_BITS;\n    *r0 = (uECC_word_t)r01;\n}\n#define muladd_exists 1\n#endif\n\nstatic void vli_mult_n(uECC_word_t *result, const uECC_word_t *left, const uECC_word_t *right) {\n    uECC_word_t r0 = 0;\n    uECC_word_t r1 = 0;\n    uECC_word_t r2 = 0;\n    wordcount_t i, k;\n\n    for (k = 0; k < uECC_N_WORDS * 2 - 1; ++k) {\n        wordcount_t min = (k < uECC_N_WORDS ? 0 : (k + 1) - uECC_N_WORDS);\n        wordcount_t max = (k < uECC_N_WORDS ? k : uECC_N_WORDS - 1);\n        for (i = min; i <= max; ++i) {\n            muladd(left[i], right[k - i], &r0, &r1, &r2);\n        }\n        result[k] = r0;\n        r0 = r1;\n        r1 = r2;\n        r2 = 0;\n    }\n    result[uECC_N_WORDS * 2 - 1] = r0;\n}\n\nstatic void vli_modAdd_n(uECC_word_t *result,\n                         const uECC_word_t *left,\n                         const uECC_word_t *right,\n                         const uECC_word_t *mod) {\n    uECC_word_t carry = vli_add_n(result, left, right);\n    if (carry || vli_cmp_n(result, mod) >= 0) {\n        vli_sub_n(result, result, mod);\n    }\n}\n\nstatic void vli_modInv_n(uECC_word_t *result, const uECC_word_t *input, const uECC_word_t *mod) {\n    uECC_word_t a[uECC_N_WORDS], b[uECC_N_WORDS], u[uECC_N_WORDS], v[uECC_N_WORDS];\n    uECC_word_t carry;\n    cmpresult_t cmpResult;\n\n    if (vli_isZero_n(input)) {\n        vli_clear_n(result);\n        return;\n    }\n\n    vli_set_n(a, input);\n    vli_set_n(b, mod);\n    vli_clear_n(u);\n    u[0] = 1;\n    vli_clear_n(v);\n    while ((cmpResult = vli_cmp_n(a, b)) != 0) {\n        carry = 0;\n        if (EVEN(a)) {\n            vli_rshift1_n(a);\n            if (!EVEN(u)) {\n                carry = vli_add_n(u, u, mod);\n            }\n            vli_rshift1_n(u);\n            if (carry) {\n                u[uECC_N_WORDS - 1] |= HIGH_BIT_SET;\n            }\n        } else if (EVEN(b)) {\n            vli_rshift1_n(b);\n            if (!EVEN(v)) {\n                carry = vli_add_n(v, v, mod);\n            }\n            vli_rshift1_n(v);\n            if (carry) {\n                v[uECC_N_WORDS - 1] |= HIGH_BIT_SET;\n            }\n        } else if (cmpResult > 0) {\n            vli_sub_n(a, a, b);\n            vli_rshift1_n(a);\n            if (vli_cmp_n(u, v) < 0) {\n                vli_add_n(u, u, mod);\n            }\n            vli_sub_n(u, u, v);\n            if (!EVEN(u)) {\n                carry = vli_add_n(u, u, mod);\n            }\n            vli_rshift1_n(u);\n            if (carry) {\n                u[uECC_N_WORDS - 1] |= HIGH_BIT_SET;\n            }\n        } else {\n            vli_sub_n(b, b, a);\n            vli_rshift1_n(b);\n            if (vli_cmp_n(v, u) < 0) {\n                vli_add_n(v, v, mod);\n            }\n            vli_sub_n(v, v, u);\n            if (!EVEN(v)) {\n                carry = vli_add_n(v, v, mod);\n            }\n            vli_rshift1_n(v);\n            if (carry) {\n                v[uECC_N_WORDS - 1] |= HIGH_BIT_SET;\n            }\n        }\n    }\n    vli_set_n(result, u);\n}\n\nstatic void vli2_rshift1_n(uECC_word_t *vli) {\n    vli_rshift1_n(vli);\n    vli[uECC_N_WORDS - 1] |= vli[uECC_N_WORDS] << (uECC_WORD_BITS - 1);\n    vli_rshift1_n(vli + uECC_N_WORDS);\n}\n\nstatic uECC_word_t vli2_sub_n(uECC_word_t *result,\n                              const uECC_word_t *left,\n                              const uECC_word_t *right) {\n    uECC_word_t borrow = 0;\n    wordcount_t i;\n    for (i = 0; i < uECC_N_WORDS * 2; ++i) {\n        uECC_word_t diff = left[i] - right[i] - borrow;\n        if (diff != left[i]) {\n            borrow = (diff > left[i]);\n        }\n        result[i] = diff;\n    }\n    return borrow;\n}\n\n/* Computes result = (left * right) % curve_n. */\nstatic void vli_modMult_n(uECC_word_t *result, const uECC_word_t *left, const uECC_word_t *right) {\n    bitcount_t i;\n    uECC_word_t product[2 * uECC_N_WORDS];\n    uECC_word_t modMultiple[2 * uECC_N_WORDS];\n    uECC_word_t tmp[2 * uECC_N_WORDS];\n    uECC_word_t *v[2] = {tmp, product};\n    uECC_word_t index = 1;\n\n    vli_mult_n(product, left, right);\n    vli_clear_n(modMultiple);\n    vli_set(modMultiple + uECC_N_WORDS + 1, curve_n);\n    vli_rshift1(modMultiple + uECC_N_WORDS + 1);\n    modMultiple[2 * uECC_N_WORDS - 1] |= HIGH_BIT_SET;\n    modMultiple[uECC_N_WORDS] = HIGH_BIT_SET;\n\n    for (i = 0;\n         i <= ((((bitcount_t)uECC_N_WORDS) << uECC_WORD_BITS_SHIFT) + (uECC_WORD_BITS - 1));\n         ++i) {\n        uECC_word_t borrow = vli2_sub_n(v[1 - index], v[index], modMultiple);\n        index = !(index ^ borrow); /* Swap the index if there was no borrow */\n        vli2_rshift1_n(modMultiple);\n    }\n    vli_set_n(result, v[index]);\n}\n\n#else\n\n#define vli_cmp_n vli_cmp\n#define vli_modInv_n vli_modInv\n#define vli_modAdd_n vli_modAdd\n\nstatic void vli2_rshift1(uECC_word_t *vli) {\n    vli_rshift1(vli);\n    vli[uECC_WORDS - 1] |= vli[uECC_WORDS] << (uECC_WORD_BITS - 1);\n    vli_rshift1(vli + uECC_WORDS);\n}\n\nstatic uECC_word_t vli2_sub(uECC_word_t *result,\n                            const uECC_word_t *left,\n                            const uECC_word_t *right) {\n    uECC_word_t borrow = 0;\n    wordcount_t i;\n    for (i = 0; i < uECC_WORDS * 2; ++i) {\n        uECC_word_t diff = left[i] - right[i] - borrow;\n        if (diff != left[i]) {\n            borrow = (diff > left[i]);\n        }\n        result[i] = diff;\n    }\n    return borrow;\n}\n\n/* Computes result = (left * right) % curve_n. */\nstatic void vli_modMult_n(uECC_word_t *result, const uECC_word_t *left, const uECC_word_t *right) {\n    uECC_word_t product[2 * uECC_WORDS];\n    uECC_word_t modMultiple[2 * uECC_WORDS];\n    uECC_word_t tmp[2 * uECC_WORDS];\n    uECC_word_t *v[2] = {tmp, product};\n    bitcount_t i;\n    uECC_word_t index = 1;\n\n    vli_mult(product, left, right);\n    vli_set(modMultiple + uECC_WORDS, curve_n); /* works if curve_n has its highest bit set */\n    vli_clear(modMultiple);\n\n    for (i = 0; i <= uECC_BYTES * 8; ++i) {\n        uECC_word_t borrow = vli2_sub(v[1 - index], v[index], modMultiple);\n        index = !(index ^ borrow); /* Swap the index if there was no borrow */\n        vli2_rshift1(modMultiple);\n    }\n    vli_set(result, v[index]);\n}\n#endif /* (uECC_CURVE != uECC_secp160r1) */\n\nstatic int uECC_sign_with_k(const uint8_t private_key[uECC_BYTES],\n                            const uint8_t message_hash[uECC_BYTES],\n                            uECC_word_t k[uECC_N_WORDS],\n                            uint8_t signature[uECC_BYTES*2]) {\n    uECC_word_t tmp[uECC_N_WORDS];\n    uECC_word_t s[uECC_N_WORDS];\n    uECC_word_t *k2[2] = {tmp, s};\n    EccPoint p;\n    uECC_word_t carry;\n    uECC_word_t tries;\n\n    /* Make sure 0 < k < curve_n */\n    if (vli_isZero(k) || vli_cmp_n(curve_n, k) != 1) {\n        return 0;\n    }\n\n#if (uECC_CURVE == uECC_secp160r1)\n    /* Make sure that we don't leak timing information about k.\n       See http://eprint.iacr.org/2011/232.pdf */\n    vli_add_n(tmp, k, curve_n);\n    carry = (tmp[uECC_WORDS] & 0x02);\n    vli_add_n(s, tmp, curve_n);\n\n    /* p = k * G */\n    EccPoint_mult(&p, &curve_G, k2[!carry], 0, (uECC_BYTES * 8) + 2);\n#else\n    /* Make sure that we don't leak timing information about k.\n       See http://eprint.iacr.org/2011/232.pdf */\n    carry = vli_add(tmp, k, curve_n);\n    vli_add(s, tmp, curve_n);\n\n    /* p = k * G */\n    EccPoint_mult(&p, &curve_G, k2[!carry], 0, (uECC_BYTES * 8) + 1);\n\n    /* r = x1 (mod n) */\n    if (vli_cmp(curve_n, p.x) != 1) {\n        vli_sub(p.x, p.x, curve_n);\n    }\n#endif\n    if (vli_isZero(p.x)) {\n        return 0;\n    }\n\n    // Attempt to get a random number to prevent side channel analysis of k.\n    // If the RNG fails every time (eg it was not defined), we continue so that\n    // deterministic signing can still work (with reduced security) without\n    // an RNG defined.\n    carry = 0; // use to signal that the RNG succeeded at least once.\n    for (tries = 0; tries < MAX_TRIES; ++tries) {\n        if (!g_rng_function((uint8_t *)tmp, sizeof(tmp))) {\n            continue;\n        }\n        carry = 1;\n        if (!vli_isZero(tmp)) {\n            break;\n        }\n    }\n    if (!carry) {\n        vli_clear(tmp);\n        tmp[0] = 1;\n    }\n\n    /* Prevent side channel analysis of vli_modInv() to determine\n       bits of k / the private key by premultiplying by a random number */\n    vli_modMult_n(k, k, tmp); /* k' = rand * k */\n    vli_modInv_n(k, k, curve_n); /* k = 1 / k' */\n    vli_modMult_n(k, k, tmp); /* k = 1 / k */\n\n    vli_nativeToBytes(signature, p.x); /* store r */\n\n    tmp[uECC_N_WORDS - 1] = 0;\n    vli_bytesToNative(tmp, private_key); /* tmp = d */\n    s[uECC_N_WORDS - 1] = 0;\n    vli_set(s, p.x);\n    vli_modMult_n(s, tmp, s); /* s = r*d */\n\n    vli_bytesToNative(tmp, message_hash);\n    vli_modAdd_n(s, tmp, s, curve_n); /* s = e + r*d */\n    vli_modMult_n(s, s, k); /* s = (e + r*d) / k */\n#if (uECC_CURVE == uECC_secp160r1)\n    if (s[uECC_N_WORDS - 1]) {\n        return 0;\n    }\n#endif\n    vli_nativeToBytes(signature + uECC_BYTES, s);\n    return 1;\n}\n\nint uECC_sign(const uint8_t private_key[uECC_BYTES],\n              const uint8_t message_hash[uECC_BYTES],\n              uint8_t signature[uECC_BYTES*2]) {\n    uECC_word_t k[uECC_N_WORDS];\n    uECC_word_t tries;\n\n    for (tries = 0; tries < MAX_TRIES; ++tries) {\n        if(g_rng_function((uint8_t *)k, sizeof(k))) {\n        #if (uECC_CURVE == uECC_secp160r1)\n            k[uECC_WORDS] &= 0x01;\n        #endif\n            if (uECC_sign_with_k(private_key, message_hash, k, signature)) {\n                return 1;\n            }\n        }\n    }\n    return 0;\n}\n\n/* Compute an HMAC using K as a key (as in RFC 6979). Note that K is always\n   the same size as the hash result size. */\nstatic void HMAC_init(uECC_HashContext *hash_context, const uint8_t *K) {\n    uint8_t *pad = hash_context->tmp + 2 * hash_context->result_size;\n    unsigned i;\n    for (i = 0; i < hash_context->result_size; ++i)\n        pad[i] = K[i] ^ 0x36;\n    for (; i < hash_context->block_size; ++i)\n        pad[i] = 0x36;\n\n    hash_context->init_hash(hash_context);\n    hash_context->update_hash(hash_context, pad, hash_context->block_size);\n}\n\nstatic void HMAC_update(uECC_HashContext *hash_context,\n                        const uint8_t *message,\n                        unsigned message_size) {\n    hash_context->update_hash(hash_context, message, message_size);\n}\n\nstatic void HMAC_finish(uECC_HashContext *hash_context, const uint8_t *K, uint8_t *result) {\n    uint8_t *pad = hash_context->tmp + 2 * hash_context->result_size;\n    unsigned i;\n    for (i = 0; i < hash_context->result_size; ++i)\n        pad[i] = K[i] ^ 0x5c;\n    for (; i < hash_context->block_size; ++i)\n        pad[i] = 0x5c;\n\n    hash_context->finish_hash(hash_context, result);\n\n    hash_context->init_hash(hash_context);\n    hash_context->update_hash(hash_context, pad, hash_context->block_size);\n    hash_context->update_hash(hash_context, result, hash_context->result_size);\n    hash_context->finish_hash(hash_context, result);\n}\n\n/* V = HMAC_K(V) */\nstatic void update_V(uECC_HashContext *hash_context, uint8_t *K, uint8_t *V) {\n    HMAC_init(hash_context, K);\n    HMAC_update(hash_context, V, hash_context->result_size);\n    HMAC_finish(hash_context, K, V);\n}\n\n/* Deterministic signing, similar to RFC 6979. Differences are:\n    * We just use (truncated) H(m) directly rather than bits2octets(H(m))\n      (it is not reduced modulo curve_n).\n    * We generate a value for k (aka T) directly rather than converting endianness.\n\n   Layout of hash_context->tmp: <K> | <V> | (1 byte overlapped 0x00 or 0x01) / <HMAC pad> */\nint uECC_sign_deterministic(const uint8_t private_key[uECC_BYTES],\n                            const uint8_t message_hash[uECC_BYTES],\n                            uECC_HashContext *hash_context,\n                            uint8_t signature[uECC_BYTES*2]) {\n    uint8_t *K = hash_context->tmp;\n    uint8_t *V = K + hash_context->result_size;\n    uECC_word_t tries;\n    unsigned i;\n    for (i = 0; i < hash_context->result_size; ++i) {\n        V[i] = 0x01;\n        K[i] = 0;\n    }\n\n    // K = HMAC_K(V || 0x00 || int2octets(x) || h(m))\n    HMAC_init(hash_context, K);\n    V[hash_context->result_size] = 0x00;\n    HMAC_update(hash_context, V, hash_context->result_size + 1);\n    HMAC_update(hash_context, private_key, uECC_BYTES);\n    HMAC_update(hash_context, message_hash, uECC_BYTES);\n    HMAC_finish(hash_context, K, K);\n\n    update_V(hash_context, K, V);\n\n    // K = HMAC_K(V || 0x01 || int2octets(x) || h(m))\n    HMAC_init(hash_context, K);\n    V[hash_context->result_size] = 0x01;\n    HMAC_update(hash_context, V, hash_context->result_size + 1);\n    HMAC_update(hash_context, private_key, uECC_BYTES);\n    HMAC_update(hash_context, message_hash, uECC_BYTES);\n    HMAC_finish(hash_context, K, K);\n\n    update_V(hash_context, K, V);\n\n    for (tries = 0; tries < MAX_TRIES; ++tries) {\n        uECC_word_t T[uECC_N_WORDS];\n        uint8_t *T_ptr = (uint8_t *)T;\n        unsigned T_bytes = 0;\n        while (T_bytes < sizeof(T)) {\n            update_V(hash_context, K, V);\n            for (i = 0; i < hash_context->result_size && T_bytes < sizeof(T); ++i, ++T_bytes) {\n                T_ptr[T_bytes] = V[i];\n            }\n        }\n    #if (uECC_CURVE == uECC_secp160r1)\n        T[uECC_WORDS] &= 0x01;\n    #endif\n\n        if (uECC_sign_with_k(private_key, message_hash, T, signature)) {\n            return 1;\n        }\n\n        // K = HMAC_K(V || 0x00)\n        HMAC_init(hash_context, K);\n        V[hash_context->result_size] = 0x00;\n        HMAC_update(hash_context, V, hash_context->result_size + 1);\n        HMAC_finish(hash_context, K, K);\n\n        update_V(hash_context, K, V);\n    }\n    return 0;\n}\n\nstatic bitcount_t smax(bitcount_t a, bitcount_t b) {\n    return (a > b ? a : b);\n}\n\nint uECC_verify(const uint8_t public_key[uECC_BYTES*2],\n                const uint8_t hash[uECC_BYTES],\n                const uint8_t signature[uECC_BYTES*2]) {\n    uECC_word_t u1[uECC_N_WORDS], u2[uECC_N_WORDS];\n    uECC_word_t z[uECC_N_WORDS];\n    EccPoint public, sum;\n    uECC_word_t rx[uECC_WORDS];\n    uECC_word_t ry[uECC_WORDS];\n    uECC_word_t tx[uECC_WORDS];\n    uECC_word_t ty[uECC_WORDS];\n    uECC_word_t tz[uECC_WORDS];\n    const EccPoint *points[4];\n    const EccPoint *point;\n    bitcount_t numBits;\n    bitcount_t i;\n    uECC_word_t r[uECC_N_WORDS], s[uECC_N_WORDS];\n    r[uECC_N_WORDS - 1] = 0;\n    s[uECC_N_WORDS - 1] = 0;\n\n    vli_bytesToNative(public.x, public_key);\n    vli_bytesToNative(public.y, public_key + uECC_BYTES);\n    vli_bytesToNative(r, signature);\n    vli_bytesToNative(s, signature + uECC_BYTES);\n\n    if (vli_isZero(r) || vli_isZero(s)) { /* r, s must not be 0. */\n        return 0;\n    }\n\n#if (uECC_CURVE != uECC_secp160r1)\n    if (vli_cmp(curve_n, r) != 1 || vli_cmp(curve_n, s) != 1) { /* r, s must be < n. */\n        return 0;\n    }\n#endif\n\n    /* Calculate u1 and u2. */\n    vli_modInv_n(z, s, curve_n); /* Z = s^-1 */\n    u1[uECC_N_WORDS - 1] = 0;\n    vli_bytesToNative(u1, hash);\n    vli_modMult_n(u1, u1, z); /* u1 = e/s */\n    vli_modMult_n(u2, r, z); /* u2 = r/s */\n\n    /* Calculate sum = G + Q. */\n    vli_set(sum.x, public.x);\n    vli_set(sum.y, public.y);\n    vli_set(tx, curve_G.x);\n    vli_set(ty, curve_G.y);\n    vli_modSub_fast(z, sum.x, tx); /* Z = x2 - x1 */\n    XYcZ_add(tx, ty, sum.x, sum.y);\n    vli_modInv(z, z, curve_p); /* Z = 1/Z */\n    apply_z(sum.x, sum.y, z);\n\n    /* Use Shamir's trick to calculate u1*G + u2*Q */\n    points[0] = 0;\n    points[1] = &curve_G;\n    points[2] = &public;\n    points[3] = &sum;\n    numBits = smax(vli_numBits(u1, uECC_N_WORDS), vli_numBits(u2, uECC_N_WORDS));\n\n    point = points[(!!vli_testBit(u1, numBits - 1)) | ((!!vli_testBit(u2, numBits - 1)) << 1)];\n    vli_set(rx, point->x);\n    vli_set(ry, point->y);\n    vli_clear(z);\n    z[0] = 1;\n\n    for (i = numBits - 2; i >= 0; --i) {\n        uECC_word_t index;\n        EccPoint_double_jacobian(rx, ry, z);\n\n        index = (!!vli_testBit(u1, i)) | ((!!vli_testBit(u2, i)) << 1);\n        point = points[index];\n        if (point) {\n            vli_set(tx, point->x);\n            vli_set(ty, point->y);\n            apply_z(tx, ty, z);\n            vli_modSub_fast(tz, rx, tx); /* Z = x2 - x1 */\n            XYcZ_add(tx, ty, rx, ry);\n            vli_modMult_fast(z, z, tz);\n        }\n    }\n\n    vli_modInv(z, z, curve_p); /* Z = 1/Z */\n    apply_z(rx, ry, z);\n\n    /* v = x1 (mod n) */\n#if (uECC_CURVE != uECC_secp160r1)\n    if (vli_cmp(curve_n, rx) != 1) {\n        vli_sub(rx, rx, curve_n);\n    }\n#endif\n\n    /* Accept only if v == r. */\n    return vli_equal(rx, r);\n}\n"
  },
  {
    "path": "tests/test_tools/uECC.h",
    "content": "/* Copyright 2014, Kenneth MacKay. Licensed under the BSD 2-clause license. */\n\n#ifndef _MICRO_ECC_H_\n#define _MICRO_ECC_H_\n\n#include <stdint.h>\n\n/* Platform selection options.\nIf uECC_PLATFORM is not defined, the code will try to guess it based on compiler macros.\nPossible values for uECC_PLATFORM are defined below: */\n#define uECC_arch_other 0\n#define uECC_x86        1\n#define uECC_x86_64     2\n#define uECC_arm        3\n#define uECC_arm_thumb  4\n#define uECC_avr        5\n#define uECC_arm_thumb2 6\n\n/* If desired, you can define uECC_WORD_SIZE as appropriate for your platform (1, 4, or 8 bytes).\nIf uECC_WORD_SIZE is not explicitly defined then it will be automatically set based on your\nplatform. */\n\n/* Inline assembly options.\nuECC_asm_none  - Use standard C99 only.\nuECC_asm_small - Use GCC inline assembly for the target platform (if available), optimized for\n                 minimum size.\nuECC_asm_fast  - Use GCC inline assembly optimized for maximum speed. */\n#define uECC_asm_none  0\n#define uECC_asm_small 1\n#define uECC_asm_fast  2\n#ifndef uECC_ASM\n    #define uECC_ASM uECC_asm_fast\n#endif\n\n/* Curve selection options. */\n#define uECC_secp160r1 1\n#define uECC_secp192r1 2\n#define uECC_secp256r1 3\n#define uECC_secp256k1 4\n#define uECC_secp224r1 5\n#ifndef uECC_CURVE\n    #define uECC_CURVE uECC_secp160r1\n#endif\n\n/* uECC_SQUARE_FUNC - If enabled (defined as nonzero), this will cause a specific function to be\nused for (scalar) squaring instead of the generic multiplication function. This will make things\nfaster by about 8% but increases the code size. */\n#ifndef uECC_SQUARE_FUNC\n    #define uECC_SQUARE_FUNC 1\n#endif\n\n#define uECC_CONCAT1(a, b) a##b\n#define uECC_CONCAT(a, b) uECC_CONCAT1(a, b)\n\n#define uECC_size_1 20 /* secp160r1 */\n#define uECC_size_2 24 /* secp192r1 */\n#define uECC_size_3 32 /* secp256r1 */\n#define uECC_size_4 32 /* secp256k1 */\n#define uECC_size_5 28 /* secp224r1 */\n\n#define uECC_BYTES uECC_CONCAT(uECC_size_, uECC_CURVE)\n\n#ifdef __cplusplus\nextern \"C\"\n{\n#endif\n\n/* uECC_RNG_Function type\nThe RNG function should fill 'size' random bytes into 'dest'. It should return 1 if\n'dest' was filled with random data, or 0 if the random data could not be generated.\nThe filled-in values should be either truly random, or from a cryptographically-secure PRNG.\n\nA correctly functioning RNG function must be set (using uECC_set_rng()) before calling\nuECC_make_key() or uECC_sign().\n\nSetting a correctly functioning RNG function improves the resistance to side-channel attacks\nfor uECC_shared_secret() and uECC_sign_deterministic().\n\nA correct RNG function is set by default when building for Windows, Linux, or OS X.\nIf you are building on another POSIX-compliant system that supports /dev/random or /dev/urandom,\nyou can define uECC_POSIX to use the predefined RNG. For embedded platforms there is no predefined\nRNG function; you must provide your own.\n*/\ntypedef int (*uECC_RNG_Function)(uint8_t *dest, unsigned size);\n\n/* uECC_set_rng() function.\nSet the function that will be used to generate random bytes. The RNG function should\nreturn 1 if the random data was generated, or 0 if the random data could not be generated.\n\nOn platforms where there is no predefined RNG function (eg embedded platforms), this must\nbe called before uECC_make_key() or uECC_sign() are used.\n\nInputs:\n    rng_function - The function that will be used to generate random bytes.\n*/\nvoid uECC_set_rng(uECC_RNG_Function rng_function);\n\n/* uECC_make_key() function.\nCreate a public/private key pair.\n\nOutputs:\n    public_key  - Will be filled in with the public key.\n    private_key - Will be filled in with the private key.\n\nReturns 1 if the key pair was generated successfully, 0 if an error occurred.\n*/\nint uECC_make_key(uint8_t public_key[uECC_BYTES*2], uint8_t private_key[uECC_BYTES]);\n\n/* uECC_shared_secret() function.\nCompute a shared secret given your secret key and someone else's public key.\nNote: It is recommended that you hash the result of uECC_shared_secret() before using it for\nsymmetric encryption or HMAC.\n\nInputs:\n    public_key  - The public key of the remote party.\n    private_key - Your private key.\n\nOutputs:\n    secret - Will be filled in with the shared secret value.\n\nReturns 1 if the shared secret was generated successfully, 0 if an error occurred.\n*/\nint uECC_shared_secret(const uint8_t public_key[uECC_BYTES*2],\n                       const uint8_t private_key[uECC_BYTES],\n                       uint8_t secret[uECC_BYTES]);\n\n/* uECC_sign() function.\nGenerate an ECDSA signature for a given hash value.\n\nUsage: Compute a hash of the data you wish to sign (SHA-2 is recommended) and pass it in to\nthis function along with your private key.\n\nInputs:\n    private_key  - Your private key.\n    message_hash - The hash of the message to sign.\n\nOutputs:\n    signature - Will be filled in with the signature value.\n\nReturns 1 if the signature generated successfully, 0 if an error occurred.\n*/\nint uECC_sign(const uint8_t private_key[uECC_BYTES],\n              const uint8_t message_hash[uECC_BYTES],\n              uint8_t signature[uECC_BYTES*2]);\n\n/* uECC_HashContext structure.\nThis is used to pass in an arbitrary hash function to uECC_sign_deterministic().\nThe structure will be used for multiple hash computations; each time a new hash\nis computed, init_hash() will be called, followed by one or more calls to\nupdate_hash(), and finally a call to finish_hash() to prudoce the resulting hash.\n\nThe intention is that you will create a structure that includes uECC_HashContext\nfollowed by any hash-specific data. For example:\n\ntypedef struct SHA256_HashContext {\n    uECC_HashContext uECC;\n    SHA256_CTX ctx;\n} SHA256_HashContext;\n\nvoid init_SHA256(uECC_HashContext *base) {\n    SHA256_HashContext *context = (SHA256_HashContext *)base;\n    SHA256_Init(&context->ctx);\n}\n\nvoid update_SHA256(uECC_HashContext *base,\n                   const uint8_t *message,\n                   unsigned message_size) {\n    SHA256_HashContext *context = (SHA256_HashContext *)base;\n    SHA256_Update(&context->ctx, message, message_size);\n}\n\nvoid finish_SHA256(uECC_HashContext *base, uint8_t *hash_result) {\n    SHA256_HashContext *context = (SHA256_HashContext *)base;\n    SHA256_Final(hash_result, &context->ctx);\n}\n\n... when signing ...\n{\n    uint8_t tmp[32 + 32 + 64];\n    SHA256_HashContext ctx = {{&init_SHA256, &update_SHA256, &finish_SHA256, 64, 32, tmp}};\n    uECC_sign_deterministic(key, message_hash, &ctx.uECC, signature);\n}\n*/\ntypedef struct uECC_HashContext {\n    void (*init_hash)(struct uECC_HashContext *context);\n    void (*update_hash)(struct uECC_HashContext *context,\n                        const uint8_t *message,\n                        unsigned message_size);\n    void (*finish_hash)(struct uECC_HashContext *context, uint8_t *hash_result);\n    unsigned block_size; /* Hash function block size in bytes, eg 64 for SHA-256. */\n    unsigned result_size; /* Hash function result size in bytes, eg 32 for SHA-256. */\n    uint8_t *tmp; /* Must point to a buffer of at least (2 * result_size + block_size) bytes. */\n} uECC_HashContext;\n\n/* uECC_sign_deterministic() function.\nGenerate an ECDSA signature for a given hash value, using a deterministic algorithm\n(see RFC 6979). You do not need to set the RNG using uECC_set_rng() before calling\nthis function; however, if the RNG is defined it will improve resistance to side-channel\nattacks.\n\nUsage: Compute a hash of the data you wish to sign (SHA-2 is recommended) and pass it in to\nthis function along with your private key and a hash context.\n\nInputs:\n    private_key  - Your private key.\n    message_hash - The hash of the message to sign.\n    hash_context - A hash context to use.\n\nOutputs:\n    signature - Will be filled in with the signature value.\n\nReturns 1 if the signature generated successfully, 0 if an error occurred.\n*/\nint uECC_sign_deterministic(const uint8_t private_key[uECC_BYTES],\n                            const uint8_t message_hash[uECC_BYTES],\n                            uECC_HashContext *hash_context,\n                            uint8_t signature[uECC_BYTES*2]);\n\n/* uECC_verify() function.\nVerify an ECDSA signature.\n\nUsage: Compute the hash of the signed data using the same hash as the signer and\npass it to this function along with the signer's public key and the signature values (r and s).\n\nInputs:\n    public_key - The signer's public key\n    hash       - The hash of the signed data.\n    signature  - The signature value.\n\nReturns 1 if the signature is valid, 0 if it is invalid.\n*/\nint uECC_verify(const uint8_t public_key[uECC_BYTES*2],\n                const uint8_t hash[uECC_BYTES],\n                const uint8_t signature[uECC_BYTES*2]);\n\n/* uECC_compress() function.\nCompress a public key.\n\nInputs:\n    public_key - The public key to compress.\n\nOutputs:\n    compressed - Will be filled in with the compressed public key.\n*/\nvoid uECC_compress(const uint8_t public_key[uECC_BYTES*2], uint8_t compressed[uECC_BYTES+1]);\n\n/* uECC_decompress() function.\nDecompress a compressed public key.\n\nInputs:\n    compressed - The compressed public key.\n\nOutputs:\n    public_key - Will be filled in with the decompressed public key.\n*/\nvoid uECC_decompress(const uint8_t compressed[uECC_BYTES+1], uint8_t public_key[uECC_BYTES*2]);\n\n/* uECC_valid_public_key() function.\nCheck to see if a public key is valid.\n\nNote that you are not required to check for a valid public key before using any other uECC\nfunctions. However, you may wish to avoid spending CPU time computing a shared secret or\nverifying a signature using an invalid public key.\n\nInputs:\n    public_key - The public key to check.\n\nReturns 1 if the public key is valid, 0 if it is invalid.\n*/\nint uECC_valid_public_key(const uint8_t public_key[uECC_BYTES*2]);\n\n/* uECC_compute_public_key() function.\nCompute the corresponding public key for a private key.\n\nInputs:\n    private_key - The private key to compute the public key for\n\nOutputs:\n    public_key - Will be filled in with the corresponding public key\n\nReturns 1 if the key was computed successfully, 0 if an error occurred.\n*/\nint uECC_compute_public_key(const uint8_t private_key[uECC_BYTES],\n                            uint8_t public_key[uECC_BYTES * 2]);\n\n\n/* uECC_bytes() function.\nReturns the value of uECC_BYTES. Helpful for foreign-interfaces to higher-level languages.\n*/\nint uECC_bytes(void);\n\n/* uECC_curve() function.\nReturns the value of uECC_CURVE. Helpful for foreign-interfaces to higher-level languages.\n*/\nint uECC_curve(void);\n\n#ifdef __cplusplus\n} /* end of extern \"C\" */\n#endif\n\n#endif /* _MICRO_ECC_H_ */\n"
  },
  {
    "path": "tests/test_tuple.hpp",
    "content": "#include <vector>\n\nnamespace test {\n    template < std::uint8_t ... Value >\n    struct tuple;\n\n\n    template < std::uint8_t V, std::uint8_t ... Values >\n    struct tuple< V, Values ... >\n    {\n        static std::vector< std::uint8_t > values()\n        {\n            std::vector< std::uint8_t > result = { V };\n            tuple< Values ... >::add_values( result );\n\n            return result;\n        }\n\n        static void add_values( std::vector< std::uint8_t >& result )\n        {\n            result.push_back( V );\n            tuple< Values ... >::add_values( result );\n        }\n    };\n\n    template <>\n    struct tuple<>\n    {\n        static std::vector< std::uint8_t > values()\n        {\n            return std::vector< std::uint8_t >();\n        }\n\n        static void add_values( std::vector< std::uint8_t >& )\n        {\n        }\n    };\n}"
  },
  {
    "path": "tests/write_queue_tests.cpp",
    "content": "#include <iostream>\n#include <bluetoe/write_queue.hpp>\n\n#define BOOST_TEST_MODULE\n#include <boost/test/included/unit_test.hpp>\n\nnamespace blued = bluetoe::details;\n\nBOOST_FIXTURE_TEST_CASE( empty_write_queue_is_instanceiable, blued::write_queue< blued::no_such_type > )\n{\n}\n\ntypedef blued::write_queue< bluetoe::shared_write_queue< 100 > > queue_100;\n\nchar client;\n\nBOOST_FIXTURE_TEST_CASE( can_allocate_98_bytes, queue_100 )\n{\n    std::uint8_t* const p = allocate_from_write_queue( 98, client );\n\n    BOOST_CHECK( p != nullptr );\n}\n\nBOOST_FIXTURE_TEST_CASE( can_allocate_98_bytes_but_not_a_single_byte_more, queue_100 )\n{\n    allocate_from_write_queue( 98, client );\n    std::uint8_t* const p = allocate_from_write_queue( 1, client );\n\n    BOOST_CHECK( p == nullptr );\n}\n\nBOOST_FIXTURE_TEST_CASE( can_allocate_multiple_times, queue_100 )\n{\n    std::uint8_t* p = nullptr;\n\n    for ( int times = 5; times; --times )\n    {\n        std::uint8_t* const new_p = allocate_from_write_queue( 15, client );\n\n        BOOST_CHECK( new_p != nullptr );\n        BOOST_CHECK( new_p != p );\n\n        p = new_p;\n    }\n}\n\nBOOST_FIXTURE_TEST_CASE( can_allocate_after_releasing, queue_100 )\n{\n    for ( int times = 5; times; --times )\n    {\n        std::uint8_t* const p = allocate_from_write_queue( 98, client );\n\n        BOOST_CHECK( p != nullptr );\n        free_write_queue( client );\n    }\n}\n\nBOOST_FIXTURE_TEST_CASE( no_first_element_in_empty_queue, queue_100 )\n{\n    BOOST_CHECK( first_write_queue_element( client ).first == nullptr );\n}\n\nBOOST_FIXTURE_TEST_CASE( queue_can_be_iterated, queue_100 )\n{\n    static const std::uint8_t test1[] = { 1, 2, 3, 4, 5 };\n    static const std::uint8_t test2[] = { 6, 7, 8 };\n    static const std::uint8_t test3[] = { 100, 101, 102, 103, 104, 105, 106 };\n\n    std::uint8_t* p1 = allocate_from_write_queue( sizeof( test1 ), client );\n    std::copy( std::begin( test1 ), std::end( test1 ), p1 );\n\n    std::uint8_t* p2 = allocate_from_write_queue( sizeof( test2 ), client );\n    std::copy( std::begin( test2 ), std::end( test2 ), p2 );\n\n    std::uint8_t* p3 = allocate_from_write_queue( sizeof( test3 ), client );\n    std::copy( std::begin( test3 ), std::end( test3 ), p3 );\n\n    std::pair< std::uint8_t*, std::size_t > ele1 = first_write_queue_element( client );\n    BOOST_CHECK_EQUAL_COLLECTIONS( ele1.first, ele1.first + ele1.second, std::begin( test1 ), std::end( test1 ) );\n\n    std::pair< std::uint8_t*, std::size_t > ele2 = next_write_queue_element( ele1.first, client );\n    BOOST_CHECK_EQUAL_COLLECTIONS( ele2.first, ele2.first + ele2.second, std::begin( test2 ), std::end( test2 ) );\n\n    std::pair< std::uint8_t*, std::size_t > ele3 = next_write_queue_element( ele2.first, client );\n    BOOST_CHECK_EQUAL_COLLECTIONS( ele3.first, ele3.first + ele3.second, std::begin( test3 ), std::end( test3 ) );\n\n    BOOST_CHECK( next_write_queue_element( ele3.first, client ).first == nullptr );\n}\n\nstruct locked_by_client1 : queue_100\n{\n    locked_by_client1()\n    {\n        BOOST_CHECK( allocate_from_write_queue( 15, client1 ) != nullptr );\n    }\n\n    char client1, client2;\n};\n\nBOOST_FIXTURE_TEST_CASE( seems_to_be_full, locked_by_client1 )\n{\n    BOOST_CHECK( allocate_from_write_queue( 15, client2 ) == nullptr );\n}\n\nBOOST_FIXTURE_TEST_CASE( but_also_seems_to_be_empty, locked_by_client1 )\n{\n    BOOST_CHECK( first_write_queue_element( client2 ).first == nullptr );\n}\n\nBOOST_FIXTURE_TEST_CASE( can_not_be_freed_by_othere_clients, locked_by_client1 )\n{\n    free_write_queue( client2 );\n    BOOST_CHECK( allocate_from_write_queue( 15, client2 ) == nullptr );\n}\n\nBOOST_FIXTURE_TEST_CASE( can_still_be_used_by_locking_client, locked_by_client1 )\n{\n    BOOST_CHECK( allocate_from_write_queue( 15, client1 ) != nullptr );\n}\n\nBOOST_FIXTURE_TEST_CASE( can_be_freed_and_allocated_again, locked_by_client1 )\n{\n    free_write_queue( client1 );\n    BOOST_CHECK( allocate_from_write_queue( 15, client2 ) != nullptr );\n}\n"
  }
]